mirror of
https://github.com/joomla-extensions/patchtester.git
synced 2024-12-22 02:49:01 +00:00
Switching to PSR-12 and updating composer dependencies
This commit is contained in:
parent
397c64c3e4
commit
8234d9a14a
15
.drone.yml
15
.drone.yml
@ -3,11 +3,13 @@ kind: pipeline
|
|||||||
name: default
|
name: default
|
||||||
|
|
||||||
clone:
|
clone:
|
||||||
depth: 42
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: composer
|
- name: composer
|
||||||
image: joomlaprojects/docker-tools:develop
|
image: joomlaprojects/docker-images:php7.4
|
||||||
|
volumes:
|
||||||
|
- name: composer-cache
|
||||||
|
path: /tmp/composer-cache
|
||||||
commands:
|
commands:
|
||||||
- composer validate --no-check-all --strict
|
- composer validate --no-check-all --strict
|
||||||
- composer install --no-progress --no-suggest
|
- composer install --no-progress --no-suggest
|
||||||
@ -16,10 +18,15 @@ steps:
|
|||||||
image: joomlaprojects/docker-images:php7.2
|
image: joomlaprojects/docker-images:php7.2
|
||||||
commands:
|
commands:
|
||||||
- echo $(date)
|
- echo $(date)
|
||||||
- ./administrator/components/com_patchtester/vendor/bin/phpcs --extensions=php -p --ignore=administrator/components/com_patchtester/vendor --standard=administrator/components/com_patchtester/vendor/joomla/cms-coding-standards/lib/Joomla-CMS administrator
|
- ./administrator/components/com_patchtester/vendor/bin/phpcs --extensions=php -p --ignore=administrator/components/com_patchtester/vendor --ignore=build/packaging --standard=PSR12 .
|
||||||
- echo $(date)
|
- echo $(date)
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: composer-cache
|
||||||
|
host:
|
||||||
|
path: /tmp/composer-cache
|
||||||
---
|
---
|
||||||
kind: signature
|
kind: signature
|
||||||
hmac: c5899584898d37d46fb70cb22487532d41719c7a836be7f67ad4ac3c2267dafa
|
hmac: 66f585c17b678699c15f48673fa52585c02eddab99c4dcfa2f1e1e85960a2a31
|
||||||
|
|
||||||
...
|
...
|
||||||
|
20
.editorconfig
Normal file
20
.editorconfig
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Unix-style end of lines and a blank line at the end of the file
|
||||||
|
[*]
|
||||||
|
indent_style = tab
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.php]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.{js,json,scss,css,vue}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -21,88 +22,81 @@ use PatchTester\Model\AbstractModel;
|
|||||||
*/
|
*/
|
||||||
abstract class AbstractController
|
abstract class AbstractController
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The active application
|
* The active application
|
||||||
*
|
*
|
||||||
* @var CMSApplication
|
* @var CMSApplication
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
protected $app;
|
protected $app;
|
||||||
|
/**
|
||||||
|
* The object context
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
protected $context;
|
||||||
|
/**
|
||||||
|
* The default view to display
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
protected $defaultView = 'pulls';
|
||||||
|
/**
|
||||||
|
* Instantiate the controller
|
||||||
|
*
|
||||||
|
* @param CMSApplication $app The application object.
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
public function __construct(CMSApplication $app)
|
||||||
|
{
|
||||||
|
$this->app = $app;
|
||||||
|
// Set the context for the controller
|
||||||
|
$this->context = 'com_patchtester.' . $this->getInput()->getCmd('view', $this->defaultView);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The object context
|
* Get the application object.
|
||||||
*
|
*
|
||||||
* @var string
|
* @return CMSApplication
|
||||||
* @since 2.0
|
*
|
||||||
*/
|
* @since 4.0.0
|
||||||
protected $context;
|
*/
|
||||||
|
public function getApplication()
|
||||||
|
{
|
||||||
|
return $this->app;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default view to display
|
* Get the input object.
|
||||||
*
|
*
|
||||||
* @var string
|
* @return Input
|
||||||
* @since 2.0
|
*
|
||||||
*/
|
* @since 4.0.0
|
||||||
protected $defaultView = 'pulls';
|
*/
|
||||||
|
public function getInput()
|
||||||
|
{
|
||||||
|
return $this->app->input;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiate the controller
|
* Sets the state for the model object
|
||||||
*
|
*
|
||||||
* @param CMSApplication $app The application object.
|
* @param AbstractModel $model Model object
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @return Registry
|
||||||
*/
|
*
|
||||||
public function __construct(CMSApplication $app)
|
* @since 2.0
|
||||||
{
|
*/
|
||||||
$this->app = $app;
|
protected function initializeState($model)
|
||||||
|
{
|
||||||
// Set the context for the controller
|
$state = new Registry();
|
||||||
$this->context = 'com_patchtester.' . $this->getInput()->getCmd('view', $this->defaultView);
|
// Load the parameters.
|
||||||
}
|
$params = ComponentHelper::getParams('com_patchtester');
|
||||||
|
$state->set('github_user', $params->get('org', 'joomla'));
|
||||||
/**
|
$state->set('github_repo', $params->get('repo', 'joomla-cms'));
|
||||||
* Get the application object.
|
return $state;
|
||||||
*
|
}
|
||||||
* @return CMSApplication
|
|
||||||
*
|
|
||||||
* @since 4.0.0
|
|
||||||
*/
|
|
||||||
public function getApplication()
|
|
||||||
{
|
|
||||||
return $this->app;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the input object.
|
|
||||||
*
|
|
||||||
* @return Input
|
|
||||||
*
|
|
||||||
* @since 4.0.0
|
|
||||||
*/
|
|
||||||
public function getInput()
|
|
||||||
{
|
|
||||||
return $this->app->input;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the state for the model object
|
|
||||||
*
|
|
||||||
* @param AbstractModel $model Model object
|
|
||||||
*
|
|
||||||
* @return Registry
|
|
||||||
*
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
|
||||||
protected function initializeState($model)
|
|
||||||
{
|
|
||||||
$state = new Registry;
|
|
||||||
|
|
||||||
// Load the parameters.
|
|
||||||
$params = ComponentHelper::getParams('com_patchtester');
|
|
||||||
|
|
||||||
$state->set('github_user', $params->get('org', 'joomla'));
|
|
||||||
$state->set('github_repo', $params->get('repo', 'joomla-cms'));
|
|
||||||
|
|
||||||
return $state;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -13,6 +14,11 @@ use Joomla\CMS\Language\Text;
|
|||||||
use Joomla\CMS\Router\Route;
|
use Joomla\CMS\Router\Route;
|
||||||
use PatchTester\Model\PullModel;
|
use PatchTester\Model\PullModel;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class to apply patches
|
* Controller class to apply patches
|
||||||
*
|
*
|
||||||
@ -20,40 +26,32 @@ use PatchTester\Model\PullModel;
|
|||||||
*/
|
*/
|
||||||
class ApplyController extends AbstractController
|
class ApplyController extends AbstractController
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Execute the controller.
|
* Execute the controller.
|
||||||
*
|
*
|
||||||
* @return void Redirects the application
|
* @return void Redirects the application
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public function execute()
|
public function execute()
|
||||||
{
|
{
|
||||||
try
|
try {
|
||||||
{
|
$model = new PullModel(null, Factory::getDbo());
|
||||||
$model = new PullModel(null, Factory::getDbo());
|
// Initialize the state for the model
|
||||||
|
$model->setState($this->initializeState($model));
|
||||||
|
if ($model->apply($this->getInput()->getUint('pull_id'))) {
|
||||||
|
$msg = Text::_('COM_PATCHTESTER_APPLY_OK');
|
||||||
|
} else {
|
||||||
|
$msg = Text::_('COM_PATCHTESTER_NO_FILES_TO_PATCH');
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the state for the model
|
$type = 'message';
|
||||||
$model->setState($this->initializeState($model));
|
} catch (\Exception $e) {
|
||||||
|
$msg = $e->getMessage();
|
||||||
|
$type = 'error';
|
||||||
|
}
|
||||||
|
|
||||||
if ($model->apply($this->getInput()->getUint('pull_id')))
|
$this->getApplication()->enqueueMessage($msg, $type);
|
||||||
{
|
$this->getApplication()->redirect(Route::_('index.php?option=com_patchtester', false));
|
||||||
$msg = Text::_('COM_PATCHTESTER_APPLY_OK');
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$msg = Text::_('COM_PATCHTESTER_NO_FILES_TO_PATCH');
|
|
||||||
}
|
|
||||||
|
|
||||||
$type = 'message';
|
|
||||||
}
|
|
||||||
catch (\Exception $e)
|
|
||||||
{
|
|
||||||
$msg = $e->getMessage();
|
|
||||||
$type = 'error';
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getApplication()->enqueueMessage($msg, $type);
|
|
||||||
$this->getApplication()->redirect(Route::_('index.php?option=com_patchtester', false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -13,6 +14,11 @@ use Joomla\CMS\Language\Text;
|
|||||||
use Joomla\Registry\Registry;
|
use Joomla\Registry\Registry;
|
||||||
use PatchTester\Model\AbstractModel;
|
use PatchTester\Model\AbstractModel;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default display controller
|
* Default display controller
|
||||||
*
|
*
|
||||||
@ -20,138 +26,110 @@ use PatchTester\Model\AbstractModel;
|
|||||||
*/
|
*/
|
||||||
class DisplayController extends AbstractController
|
class DisplayController extends AbstractController
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Default ordering value
|
* Default ordering value
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
protected $defaultFullOrdering = 'a.pull_id DESC';
|
protected $defaultFullOrdering = 'a.pull_id DESC';
|
||||||
|
/**
|
||||||
|
* Execute the controller.
|
||||||
|
*
|
||||||
|
* @return boolean True on success
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
|
public function execute()
|
||||||
|
{
|
||||||
|
// Set up variables to build our classes
|
||||||
|
$view = $this->getInput()->getCmd('view', $this->defaultView);
|
||||||
|
$format = $this->getInput()->getCmd('format', 'html');
|
||||||
|
// Register the layout paths for the view
|
||||||
|
$paths = new \SplPriorityQueue();
|
||||||
|
// Add the path for template overrides
|
||||||
|
$paths->insert(JPATH_THEMES . '/' . $this->getApplication()->getTemplate() . '/html/com_patchtester/' . $view, 2);
|
||||||
|
// Add the path for the default layouts
|
||||||
|
$paths->insert(dirname(__DIR__) . '/View/' . ucfirst($view) . '/tmpl', 1);
|
||||||
|
// Build the class names for the model and view
|
||||||
|
$viewClass = '\\PatchTester\\View\\' . ucfirst($view) . '\\' . ucfirst($view) . ucfirst($format) . 'View';
|
||||||
|
$modelClass = '\\PatchTester\\Model\\' . ucfirst($view) . 'Model';
|
||||||
|
// Sanity check - Ensure our classes exist
|
||||||
|
if (!class_exists($viewClass)) {
|
||||||
|
// Try to use a default view
|
||||||
|
$viewClass = '\\PatchTester\\View\\Default' . ucfirst($format) . 'View';
|
||||||
|
if (!class_exists($viewClass)) {
|
||||||
|
throw new \RuntimeException(Text::sprintf('COM_PATCHTESTER_ERROR_VIEW_NOT_FOUND', $view, $format), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
if (!class_exists($modelClass)) {
|
||||||
* Execute the controller.
|
throw new \RuntimeException(Text::sprintf('COM_PATCHTESTER_ERROR_MODEL_NOT_FOUND', $modelClass), 500);
|
||||||
*
|
}
|
||||||
* @return boolean True on success
|
|
||||||
*
|
|
||||||
* @since 2.0
|
|
||||||
* @throws \RuntimeException
|
|
||||||
*/
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
// Set up variables to build our classes
|
|
||||||
$view = $this->getInput()->getCmd('view', $this->defaultView);
|
|
||||||
$format = $this->getInput()->getCmd('format', 'html');
|
|
||||||
|
|
||||||
// Register the layout paths for the view
|
// Initialize the model class now; need to do it before setting the state to get required data from it
|
||||||
$paths = new \SplPriorityQueue;
|
$model = new $modelClass($this->context, null, Factory::getDbo());
|
||||||
|
// Initialize the state for the model
|
||||||
|
$state = $this->initializeState($model);
|
||||||
|
foreach ($state as $key => $value) {
|
||||||
|
$model->setState($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
// Add the path for template overrides
|
// Initialize the view class now
|
||||||
$paths->insert(JPATH_THEMES . '/' . $this->getApplication()->getTemplate() . '/html/com_patchtester/' . $view, 2);
|
$view = new $viewClass($model, $paths);
|
||||||
|
// Echo the rendered view for the application
|
||||||
|
echo $view->render();
|
||||||
|
// Finished!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Add the path for the default layouts
|
/**
|
||||||
$paths->insert(dirname(__DIR__) . '/View/' . ucfirst($view) . '/tmpl', 1);
|
* Sets the state for the model object
|
||||||
|
*
|
||||||
|
* @param AbstractModel $model Model object
|
||||||
|
*
|
||||||
|
* @return Registry
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
protected function initializeState($model)
|
||||||
|
{
|
||||||
|
$state = parent::initializeState($model);
|
||||||
|
$app = $this->getApplication();
|
||||||
|
// Load the filter state.
|
||||||
|
$state->set('filter.search', $app->getUserStateFromRequest($this->context . '.filter.search', 'filter_search', ''));
|
||||||
|
$state->set('filter.applied', $app->getUserStateFromRequest($this->context . '.filter.applied', 'filter_applied', ''));
|
||||||
|
$state->set('filter.branch', $app->getUserStateFromRequest($this->context . '.filter.branch', 'filter_branch', ''));
|
||||||
|
$state->set('filter.rtc', $app->getUserStateFromRequest($this->context . '.filter.rtc', 'filter_rtc', ''));
|
||||||
|
$state->set('filter.npm', $app->getUserStateFromRequest($this->context . '.filter.npm', 'filter_npm', ''));
|
||||||
|
$state->set('filter.label', $app->getUserStateFromRequest($this->context . '.filter.label', 'filter_label', ''));
|
||||||
|
// Pre-fill the limits.
|
||||||
|
$limit = $app->getUserStateFromRequest('global.list.limit', 'limit', $app->input->get('list_limit', 20), 'uint');
|
||||||
|
$state->set('list.limit', $limit);
|
||||||
|
$fullOrdering = $app->getUserStateFromRequest($this->context . '.fullorder', 'list_fullordering', $this->defaultFullOrdering);
|
||||||
|
$orderingParts = explode(' ', $fullOrdering);
|
||||||
|
if (count($orderingParts) !== 2) {
|
||||||
|
$fullOrdering = $this->defaultFullOrdering;
|
||||||
|
$orderingParts = explode(' ', $fullOrdering);
|
||||||
|
}
|
||||||
|
|
||||||
// Build the class names for the model and view
|
$state->set('list.fullordering', $fullOrdering);
|
||||||
$viewClass = '\\PatchTester\\View\\' . ucfirst($view) . '\\' . ucfirst($view) . ucfirst($format) . 'View';
|
// The 2nd part will be considered the direction
|
||||||
$modelClass = '\\PatchTester\\Model\\' . ucfirst($view) . 'Model';
|
$direction = $orderingParts[array_key_last($orderingParts)];
|
||||||
|
if (in_array(strtoupper($direction), ['ASC', 'DESC', ''])) {
|
||||||
|
$state->set('list.direction', $direction);
|
||||||
|
}
|
||||||
|
|
||||||
// Sanity check - Ensure our classes exist
|
// The 1st part will be the ordering
|
||||||
if (!class_exists($viewClass))
|
$ordering = $orderingParts[array_key_first($orderingParts)];
|
||||||
{
|
if (in_array($ordering, $model->getSortFields())) {
|
||||||
// Try to use a default view
|
$state->set('list.ordering', $ordering);
|
||||||
$viewClass = '\\PatchTester\\View\\Default' . ucfirst($format) . 'View';
|
}
|
||||||
|
|
||||||
if (!class_exists($viewClass))
|
$value = $app->getUserStateFromRequest($this->context . '.limitstart', 'limitstart', 0);
|
||||||
{
|
$limitstart = ($limit != 0 ? (floor($value / $limit) * $limit) : 0);
|
||||||
throw new \RuntimeException(Text::sprintf('COM_PATCHTESTER_ERROR_VIEW_NOT_FOUND', $view, $format), 500);
|
$state->set('list.start', $limitstart);
|
||||||
}
|
return $state;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!class_exists($modelClass))
|
|
||||||
{
|
|
||||||
throw new \RuntimeException(Text::sprintf('COM_PATCHTESTER_ERROR_MODEL_NOT_FOUND', $modelClass), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the model class now; need to do it before setting the state to get required data from it
|
|
||||||
$model = new $modelClass($this->context, null, Factory::getDbo());
|
|
||||||
|
|
||||||
// Initialize the state for the model
|
|
||||||
$state = $this->initializeState($model);
|
|
||||||
|
|
||||||
foreach ($state as $key => $value)
|
|
||||||
{
|
|
||||||
$model->setState($key, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the view class now
|
|
||||||
$view = new $viewClass($model, $paths);
|
|
||||||
|
|
||||||
// Echo the rendered view for the application
|
|
||||||
echo $view->render();
|
|
||||||
|
|
||||||
// Finished!
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the state for the model object
|
|
||||||
*
|
|
||||||
* @param AbstractModel $model Model object
|
|
||||||
*
|
|
||||||
* @return Registry
|
|
||||||
*
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
|
||||||
protected function initializeState($model)
|
|
||||||
{
|
|
||||||
$state = parent::initializeState($model);
|
|
||||||
$app = $this->getApplication();
|
|
||||||
|
|
||||||
// Load the filter state.
|
|
||||||
$state->set('filter.search', $app->getUserStateFromRequest($this->context . '.filter.search', 'filter_search', ''));
|
|
||||||
$state->set('filter.applied', $app->getUserStateFromRequest($this->context . '.filter.applied', 'filter_applied', ''));
|
|
||||||
$state->set('filter.branch', $app->getUserStateFromRequest($this->context . '.filter.branch', 'filter_branch', ''));
|
|
||||||
$state->set('filter.rtc', $app->getUserStateFromRequest($this->context . '.filter.rtc', 'filter_rtc', ''));
|
|
||||||
$state->set('filter.npm', $app->getUserStateFromRequest($this->context . '.filter.npm', 'filter_npm', ''));
|
|
||||||
$state->set('filter.label', $app->getUserStateFromRequest($this->context . '.filter.label', 'filter_label', ''));
|
|
||||||
|
|
||||||
// Pre-fill the limits.
|
|
||||||
$limit = $app->getUserStateFromRequest('global.list.limit', 'limit', $app->input->get('list_limit', 20), 'uint');
|
|
||||||
$state->set('list.limit', $limit);
|
|
||||||
|
|
||||||
$fullOrdering = $app->getUserStateFromRequest($this->context . '.fullorder', 'list_fullordering', $this->defaultFullOrdering);
|
|
||||||
|
|
||||||
$orderingParts = explode(' ', $fullOrdering);
|
|
||||||
|
|
||||||
if (count($orderingParts) !== 2)
|
|
||||||
{
|
|
||||||
$fullOrdering = $this->defaultFullOrdering;
|
|
||||||
|
|
||||||
$orderingParts = explode(' ', $fullOrdering);
|
|
||||||
}
|
|
||||||
|
|
||||||
$state->set('list.fullordering', $fullOrdering);
|
|
||||||
|
|
||||||
// The 2nd part will be considered the direction
|
|
||||||
$direction = $orderingParts[array_key_last($orderingParts)];
|
|
||||||
|
|
||||||
if (in_array(strtoupper($direction), ['ASC', 'DESC', '']))
|
|
||||||
{
|
|
||||||
$state->set('list.direction', $direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The 1st part will be the ordering
|
|
||||||
$ordering = $orderingParts[array_key_first($orderingParts)];
|
|
||||||
|
|
||||||
if (in_array($ordering, $model->getSortFields()))
|
|
||||||
{
|
|
||||||
$state->set('list.ordering', $ordering);
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = $app->getUserStateFromRequest($this->context . '.limitstart', 'limitstart', 0);
|
|
||||||
$limitstart = ($limit != 0 ? (floor($value / $limit) * $limit) : 0);
|
|
||||||
$state->set('list.start', $limitstart);
|
|
||||||
|
|
||||||
return $state;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -13,6 +14,10 @@ use Joomla\CMS\Language\Text;
|
|||||||
use Joomla\CMS\Response\JsonResponse;
|
use Joomla\CMS\Response\JsonResponse;
|
||||||
use PatchTester\Model\PullsModel;
|
use PatchTester\Model\PullsModel;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class to fetch remote data
|
* Controller class to fetch remote data
|
||||||
*
|
*
|
||||||
@ -20,84 +25,66 @@ use PatchTester\Model\PullsModel;
|
|||||||
*/
|
*/
|
||||||
class FetchController extends AbstractController
|
class FetchController extends AbstractController
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Execute the controller.
|
* Execute the controller.
|
||||||
*
|
*
|
||||||
* @return void Redirects the application
|
* @return void Redirects the application
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public function execute()
|
public function execute()
|
||||||
{
|
{
|
||||||
// We don't want this request to be cached.
|
// We don't want this request to be cached.
|
||||||
$this->getApplication()->setHeader('Expires', 'Mon, 1 Jan 2001 00:00:00 GMT', true);
|
$this->getApplication()->setHeader('Expires', 'Mon, 1 Jan 2001 00:00:00 GMT', true);
|
||||||
$this->getApplication()->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT', true);
|
$this->getApplication()->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT', true);
|
||||||
$this->getApplication()->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', false);
|
$this->getApplication()->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', false);
|
||||||
$this->getApplication()->setHeader('Pragma', 'no-cache');
|
$this->getApplication()->setHeader('Pragma', 'no-cache');
|
||||||
$this->getApplication()->setHeader('Content-Type', $this->getApplication()->mimeType . '; charset=' . $this->getApplication()->charSet);
|
$this->getApplication()->setHeader('Content-Type', $this->getApplication()->mimeType . '; charset=' . $this->getApplication()->charSet);
|
||||||
|
$session = Factory::getSession();
|
||||||
|
try {
|
||||||
|
// Fetch our page from the session
|
||||||
|
$page = $session->get('com_patchtester_fetcher_page', 1);
|
||||||
|
$model = new PullsModel();
|
||||||
|
// Initialize the state for the model
|
||||||
|
$state = $this->initializeState($model);
|
||||||
|
foreach ($state as $key => $value) {
|
||||||
|
$model->setState($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
$session = Factory::getSession();
|
$status = $model->requestFromGithub($page);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$response = new JsonResponse($e);
|
||||||
|
$this->getApplication()->sendHeaders();
|
||||||
|
echo json_encode($response);
|
||||||
|
$this->getApplication()->close(1);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
// Store the last page to the session if given one
|
||||||
{
|
if (isset($status['lastPage']) && $status['lastPage'] !== false) {
|
||||||
// Fetch our page from the session
|
$session->set('com_patchtester_fetcher_last_page', $status['lastPage']);
|
||||||
$page = $session->get('com_patchtester_fetcher_page', 1);
|
}
|
||||||
|
|
||||||
$model = new PullsModel;
|
// Update the UI and session now
|
||||||
|
if ($status['complete'] || $page === $session->get('com_patchtester_fetcher_last_page', false)) {
|
||||||
|
$status['complete'] = true;
|
||||||
|
$status['header'] = Text::_('COM_PATCHTESTER_FETCH_SUCCESSFUL', true);
|
||||||
|
$message = Text::_('COM_PATCHTESTER_FETCH_COMPLETE_CLOSE_WINDOW', true);
|
||||||
|
} elseif (isset($status['page'])) {
|
||||||
|
$session->set('com_patchtester_fetcher_page', $status['page']);
|
||||||
|
$message = Text::sprintf('COM_PATCHTESTER_FETCH_PAGE_NUMBER', $status['page']);
|
||||||
|
|
||||||
// Initialize the state for the model
|
if ($session->has('com_patchtester_fetcher_last_page')) {
|
||||||
$state = $this->initializeState($model);
|
$message = Text::sprintf(
|
||||||
|
'COM_PATCHTESTER_FETCH_PAGE_NUMBER_OF_TOTAL',
|
||||||
|
$status['page'],
|
||||||
|
$session->get('com_patchtester_fetcher_last_page')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($state as $key => $value)
|
$response = new JsonResponse($status, $message, false, true);
|
||||||
{
|
$this->getApplication()->sendHeaders();
|
||||||
$model->setState($key, $value);
|
echo json_encode($response);
|
||||||
}
|
$this->getApplication()->close();
|
||||||
|
}
|
||||||
$status = $model->requestFromGithub($page);
|
|
||||||
}
|
|
||||||
catch (\Exception $e)
|
|
||||||
{
|
|
||||||
$response = new JsonResponse($e);
|
|
||||||
|
|
||||||
$this->getApplication()->sendHeaders();
|
|
||||||
echo json_encode($response);
|
|
||||||
|
|
||||||
$this->getApplication()->close(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the last page to the session if given one
|
|
||||||
if (isset($status['lastPage']) && $status['lastPage'] !== false)
|
|
||||||
{
|
|
||||||
$session->set('com_patchtester_fetcher_last_page', $status['lastPage']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the UI and session now
|
|
||||||
if ($status['complete'] || $page === $session->get('com_patchtester_fetcher_last_page', false))
|
|
||||||
{
|
|
||||||
$status['complete'] = true;
|
|
||||||
$status['header'] = Text::_('COM_PATCHTESTER_FETCH_SUCCESSFUL', true);
|
|
||||||
|
|
||||||
$message = Text::_('COM_PATCHTESTER_FETCH_COMPLETE_CLOSE_WINDOW', true);
|
|
||||||
}
|
|
||||||
elseif (isset($status['page']))
|
|
||||||
{
|
|
||||||
$session->set('com_patchtester_fetcher_page', $status['page']);
|
|
||||||
|
|
||||||
$message = Text::sprintf('COM_PATCHTESTER_FETCH_PAGE_NUMBER', $status['page']);
|
|
||||||
|
|
||||||
if ($session->has('com_patchtester_fetcher_last_page'))
|
|
||||||
{
|
|
||||||
$message = Text::sprintf(
|
|
||||||
'COM_PATCHTESTER_FETCH_PAGE_NUMBER_OF_TOTAL', $status['page'], $session->get('com_patchtester_fetcher_last_page')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = new JsonResponse($status, $message, false, true);
|
|
||||||
|
|
||||||
$this->getApplication()->sendHeaders();
|
|
||||||
echo json_encode($response);
|
|
||||||
|
|
||||||
$this->getApplication()->close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -18,6 +19,10 @@ use PatchTester\Model\PullModel;
|
|||||||
use PatchTester\Model\PullsModel;
|
use PatchTester\Model\PullsModel;
|
||||||
use PatchTester\Model\TestsModel;
|
use PatchTester\Model\TestsModel;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class to reset the system state
|
* Controller class to reset the system state
|
||||||
*
|
*
|
||||||
@ -25,131 +30,104 @@ use PatchTester\Model\TestsModel;
|
|||||||
*/
|
*/
|
||||||
class ResetController extends AbstractController
|
class ResetController extends AbstractController
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Execute the controller.
|
* Execute the controller.
|
||||||
*
|
*
|
||||||
* @return void Redirects the application
|
* @return void Redirects the application
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public function execute(): void
|
public function execute(): void
|
||||||
{
|
{
|
||||||
try
|
try {
|
||||||
{
|
$hasErrors = false;
|
||||||
$hasErrors = false;
|
$revertErrored = false;
|
||||||
$revertErrored = false;
|
$pullModel = new PullModel(null, Factory::getDbo());
|
||||||
|
$pullsModel = new PullsModel($this->context, null, Factory::getDbo());
|
||||||
|
$testsModel = new TestsModel(null, Factory::getDbo());
|
||||||
|
// Check the applied patches in the database first
|
||||||
|
$appliedPatches = $testsModel->getAppliedPatches();
|
||||||
|
$params = ComponentHelper::getParams('com_patchtester');
|
||||||
|
// Decide based on repository settings whether patch will be applied through Github or CIServer
|
||||||
|
if ((bool) $params->get('ci_switch', 1)) {
|
||||||
|
// Let's try to cleanly revert all applied patches with ci
|
||||||
|
foreach ($appliedPatches as $patch) {
|
||||||
|
try {
|
||||||
|
$pullModel->revertWithCIServer($patch->id);
|
||||||
|
} catch (\RuntimeException $e) {
|
||||||
|
$revertErrored = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Let's try to cleanly revert all applied patches
|
||||||
|
foreach ($appliedPatches as $patch) {
|
||||||
|
try {
|
||||||
|
$pullModel->revertWithGitHub($patch->id);
|
||||||
|
} catch (\RuntimeException $e) {
|
||||||
|
$revertErrored = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$pullModel = new PullModel(null, Factory::getDbo());
|
// If we errored out reverting patches, we'll need to truncate the table
|
||||||
$pullsModel = new PullsModel($this->context, null, Factory::getDbo());
|
if ($revertErrored) {
|
||||||
$testsModel = new TestsModel(null, Factory::getDbo());
|
try {
|
||||||
|
$testsModel->truncateTable();
|
||||||
|
} catch (\RuntimeException $e) {
|
||||||
|
$hasErrors = true;
|
||||||
|
|
||||||
// Check the applied patches in the database first
|
$this->getApplication()->enqueueMessage(
|
||||||
$appliedPatches = $testsModel->getAppliedPatches();
|
Text::sprintf('COM_PATCHTESTER_ERROR_TRUNCATING_PULLS_TABLE', $e->getMessage()),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$params = ComponentHelper::getParams('com_patchtester');
|
// Now truncate the pulls table
|
||||||
|
try {
|
||||||
|
$pullsModel->truncateTable();
|
||||||
|
} catch (\RuntimeException $e) {
|
||||||
|
$hasErrors = true;
|
||||||
|
|
||||||
// Decide based on repository settings whether patch will be applied through Github or CIServer
|
$this->getApplication()->enqueueMessage(
|
||||||
if ((bool) $params->get('ci_switch', 1))
|
Text::sprintf('COM_PATCHTESTER_ERROR_TRUNCATING_TESTS_TABLE', $e->getMessage()),
|
||||||
{
|
'error'
|
||||||
// Let's try to cleanly revert all applied patches with ci
|
);
|
||||||
foreach ($appliedPatches as $patch)
|
}
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$pullModel->revertWithCIServer($patch->id);
|
|
||||||
}
|
|
||||||
catch (\RuntimeException $e)
|
|
||||||
{
|
|
||||||
$revertErrored = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Let's try to cleanly revert all applied patches
|
|
||||||
foreach ($appliedPatches as $patch)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$pullModel->revertWithGitHub($patch->id);
|
|
||||||
}
|
|
||||||
catch (\RuntimeException $e)
|
|
||||||
{
|
|
||||||
$revertErrored = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we errored out reverting patches, we'll need to truncate the table
|
// Check the backups directory to see if any .txt files remain; clear them if so
|
||||||
if ($revertErrored)
|
$backups = Folder::files(JPATH_COMPONENT . '/backups', '.txt');
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$testsModel->truncateTable();
|
|
||||||
}
|
|
||||||
catch (\RuntimeException $e)
|
|
||||||
{
|
|
||||||
$hasErrors = true;
|
|
||||||
|
|
||||||
$this->getApplication()->enqueueMessage(
|
if (count($backups)) {
|
||||||
Text::sprintf('COM_PATCHTESTER_ERROR_TRUNCATING_PULLS_TABLE', $e->getMessage()), 'error'
|
foreach ($backups as $file) {
|
||||||
);
|
if (!File::delete(JPATH_COMPONENT . '/backups/' . $file)) {
|
||||||
}
|
$this->getApplication()->enqueueMessage(
|
||||||
}
|
Text::sprintf('COM_PATCHTESTER_ERROR_CANNOT_DELETE_FILE', JPATH_COMPONENT . '/backups/' . $file),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
$hasErrors = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Now truncate the pulls table
|
// Processing completed, inform the user of a success or fail
|
||||||
try
|
if ($hasErrors) {
|
||||||
{
|
$msg = Text::sprintf(
|
||||||
$pullsModel->truncateTable();
|
'COM_PATCHTESTER_RESET_HAS_ERRORS',
|
||||||
}
|
JPATH_COMPONENT . '/backups',
|
||||||
catch (\RuntimeException $e)
|
Factory::getDbo()->replacePrefix('#__patchtester_tests')
|
||||||
{
|
);
|
||||||
$hasErrors = true;
|
$type = 'warning';
|
||||||
|
} else {
|
||||||
|
$msg = Text::_('COM_PATCHTESTER_RESET_OK');
|
||||||
|
$type = 'notice';
|
||||||
|
}
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
$msg = $exception->getMessage();
|
||||||
|
$type = 'error';
|
||||||
|
}
|
||||||
|
|
||||||
$this->getApplication()->enqueueMessage(
|
$this->getApplication()->enqueueMessage($msg, $type);
|
||||||
Text::sprintf('COM_PATCHTESTER_ERROR_TRUNCATING_TESTS_TABLE', $e->getMessage()), 'error'
|
$this->getApplication()->redirect(Route::_('index.php?option=com_patchtester', false));
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Check the backups directory to see if any .txt files remain; clear them if so
|
|
||||||
$backups = Folder::files(JPATH_COMPONENT . '/backups', '.txt');
|
|
||||||
|
|
||||||
if (count($backups))
|
|
||||||
{
|
|
||||||
foreach ($backups as $file)
|
|
||||||
{
|
|
||||||
if (!File::delete(JPATH_COMPONENT . '/backups/' . $file))
|
|
||||||
{
|
|
||||||
$this->getApplication()->enqueueMessage(
|
|
||||||
Text::sprintf('COM_PATCHTESTER_ERROR_CANNOT_DELETE_FILE', JPATH_COMPONENT . '/backups/' . $file), 'error'
|
|
||||||
);
|
|
||||||
|
|
||||||
$hasErrors = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Processing completed, inform the user of a success or fail
|
|
||||||
if ($hasErrors)
|
|
||||||
{
|
|
||||||
$msg = Text::sprintf(
|
|
||||||
'COM_PATCHTESTER_RESET_HAS_ERRORS', JPATH_COMPONENT . '/backups', Factory::getDbo()->replacePrefix('#__patchtester_tests')
|
|
||||||
);
|
|
||||||
$type = 'warning';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$msg = Text::_('COM_PATCHTESTER_RESET_OK');
|
|
||||||
$type = 'notice';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (\Exception $exception)
|
|
||||||
{
|
|
||||||
$msg = $exception->getMessage();
|
|
||||||
$type = 'error';
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getApplication()->enqueueMessage($msg, $type);
|
|
||||||
$this->getApplication()->redirect(Route::_('index.php?option=com_patchtester', false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -13,6 +14,10 @@ use Joomla\CMS\Language\Text;
|
|||||||
use Joomla\CMS\Router\Route;
|
use Joomla\CMS\Router\Route;
|
||||||
use PatchTester\Model\PullModel;
|
use PatchTester\Model\PullModel;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class to revert patches
|
* Controller class to revert patches
|
||||||
*
|
*
|
||||||
@ -20,34 +25,28 @@ use PatchTester\Model\PullModel;
|
|||||||
*/
|
*/
|
||||||
class RevertController extends AbstractController
|
class RevertController extends AbstractController
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Execute the controller.
|
* Execute the controller.
|
||||||
*
|
*
|
||||||
* @return void Redirects the application
|
* @return void Redirects the application
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public function execute()
|
public function execute()
|
||||||
{
|
{
|
||||||
try
|
try {
|
||||||
{
|
$model = new PullModel(null, Factory::getDbo());
|
||||||
$model = new PullModel(null, Factory::getDbo());
|
// Initialize the state for the model
|
||||||
|
$model->setState($this->initializeState($model));
|
||||||
|
$model->revert($this->getInput()->getUint('pull_id'));
|
||||||
|
$msg = Text::_('COM_PATCHTESTER_REVERT_OK');
|
||||||
|
$type = 'message';
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$msg = $e->getMessage();
|
||||||
|
$type = 'error';
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the state for the model
|
$this->getApplication()->enqueueMessage($msg, $type);
|
||||||
$model->setState($this->initializeState($model));
|
$this->getApplication()->redirect(Route::_('index.php?option=com_patchtester', false));
|
||||||
|
}
|
||||||
$model->revert($this->getInput()->getUint('pull_id'));
|
|
||||||
|
|
||||||
$msg = Text::_('COM_PATCHTESTER_REVERT_OK');
|
|
||||||
$type = 'message';
|
|
||||||
}
|
|
||||||
catch (\Exception $e)
|
|
||||||
{
|
|
||||||
$msg = $e->getMessage();
|
|
||||||
$type = 'error';
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getApplication()->enqueueMessage($msg, $type);
|
|
||||||
$this->getApplication()->redirect(Route::_('index.php?option=com_patchtester', false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -15,6 +16,10 @@ use Joomla\CMS\Session\Session;
|
|||||||
use PatchTester\Helper;
|
use PatchTester\Helper;
|
||||||
use PatchTester\Model\TestsModel;
|
use PatchTester\Model\TestsModel;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class to start fetching remote data
|
* Controller class to start fetching remote data
|
||||||
*
|
*
|
||||||
@ -22,109 +27,69 @@ use PatchTester\Model\TestsModel;
|
|||||||
*/
|
*/
|
||||||
class StartfetchController extends AbstractController
|
class StartfetchController extends AbstractController
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Execute the controller.
|
* Execute the controller.
|
||||||
*
|
*
|
||||||
* @return void Redirects the application
|
* @return void Redirects the application
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public function execute()
|
public function execute()
|
||||||
{
|
{
|
||||||
// We don't want this request to be cached.
|
// We don't want this request to be cached.
|
||||||
$this->getApplication()->setHeader('Expires', 'Mon, 1 Jan 2001 00:00:00 GMT', true);
|
$this->getApplication()->setHeader('Expires', 'Mon, 1 Jan 2001 00:00:00 GMT', true);
|
||||||
$this->getApplication()->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT', true);
|
$this->getApplication()->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT', true);
|
||||||
$this->getApplication()->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', false);
|
$this->getApplication()->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', false);
|
||||||
$this->getApplication()->setHeader('Pragma', 'no-cache');
|
$this->getApplication()->setHeader('Pragma', 'no-cache');
|
||||||
$this->getApplication()->setHeader('Content-Type', $this->getApplication()->mimeType . '; charset=' . $this->getApplication()->charSet);
|
$this->getApplication()->setHeader('Content-Type', $this->getApplication()->mimeType . '; charset=' . $this->getApplication()->charSet);
|
||||||
|
// Check for a valid token. If invalid, send a 403 with the error message.
|
||||||
|
if (!Session::checkToken('request')) {
|
||||||
|
$response = new JsonResponse(new \Exception(Text::_('JINVALID_TOKEN'), 403));
|
||||||
|
$this->getApplication()->sendHeaders();
|
||||||
|
echo json_encode($response);
|
||||||
|
$this->getApplication()->close(1);
|
||||||
|
}
|
||||||
|
|
||||||
// Check for a valid token. If invalid, send a 403 with the error message.
|
// Make sure we can fetch the data from GitHub - throw an error on < 10 available requests
|
||||||
if (!Session::checkToken('request'))
|
try {
|
||||||
{
|
$rateResponse = Helper::initializeGithub()->getRateLimit();
|
||||||
$response = new JsonResponse(new \Exception(Text::_('JINVALID_TOKEN'), 403));
|
$rate = json_decode($rateResponse->body);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$response = new JsonResponse(new \Exception(Text::sprintf('COM_PATCHTESTER_COULD_NOT_CONNECT_TO_GITHUB', $e->getMessage()), $e->getCode(), $e));
|
||||||
|
$this->getApplication()->sendHeaders();
|
||||||
|
echo json_encode($response);
|
||||||
|
$this->getApplication()->close(1);
|
||||||
|
}
|
||||||
|
|
||||||
$this->getApplication()->sendHeaders();
|
// If over the API limit, we can't build this list
|
||||||
echo json_encode($response);
|
if ($rate->resources->core->remaining < 10) {
|
||||||
|
$response = new JsonResponse(new \Exception(Text::sprintf('COM_PATCHTESTER_API_LIMIT_LIST', Factory::getDate($rate->resources->core->reset)), 429));
|
||||||
|
$this->getApplication()->sendHeaders();
|
||||||
|
echo json_encode($response);
|
||||||
|
$this->getApplication()->close(1);
|
||||||
|
}
|
||||||
|
|
||||||
$this->getApplication()->close(1);
|
$testsModel = new TestsModel(null, Factory::getDbo());
|
||||||
}
|
try {
|
||||||
|
// Sanity check, ensure there aren't any applied patches
|
||||||
|
if (count($testsModel->getAppliedPatches()) >= 1) {
|
||||||
|
$response = new JsonResponse(new \Exception(Text::_('COM_PATCHTESTER_ERROR_APPLIED_PATCHES'), 500));
|
||||||
|
$this->getApplication()->sendHeaders();
|
||||||
|
echo json_encode($response);
|
||||||
|
$this->getApplication()->close(1);
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$response = new JsonResponse($e);
|
||||||
|
$this->getApplication()->sendHeaders();
|
||||||
|
echo json_encode($response);
|
||||||
|
$this->getApplication()->close(1);
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure we can fetch the data from GitHub - throw an error on < 10 available requests
|
// We're able to successfully pull data, prepare our environment
|
||||||
try
|
Factory::getSession()->set('com_patchtester_fetcher_page', 1);
|
||||||
{
|
$response = new JsonResponse(array('complete' => false, 'header' => Text::_('COM_PATCHTESTER_FETCH_PROCESSING', true)), Text::sprintf('COM_PATCHTESTER_FETCH_PAGE_NUMBER', 1), false, true);
|
||||||
$rateResponse = Helper::initializeGithub()->getRateLimit();
|
$this->getApplication()->sendHeaders();
|
||||||
$rate = json_decode($rateResponse->body);
|
echo json_encode($response);
|
||||||
}
|
$this->getApplication()->close();
|
||||||
catch (\Exception $e)
|
}
|
||||||
{
|
|
||||||
$response = new JsonResponse(
|
|
||||||
new \Exception(
|
|
||||||
Text::sprintf('COM_PATCHTESTER_COULD_NOT_CONNECT_TO_GITHUB', $e->getMessage()),
|
|
||||||
$e->getCode(),
|
|
||||||
$e
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->getApplication()->sendHeaders();
|
|
||||||
echo json_encode($response);
|
|
||||||
|
|
||||||
$this->getApplication()->close(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If over the API limit, we can't build this list
|
|
||||||
if ($rate->resources->core->remaining < 10)
|
|
||||||
{
|
|
||||||
$response = new JsonResponse(
|
|
||||||
new \Exception(
|
|
||||||
Text::sprintf('COM_PATCHTESTER_API_LIMIT_LIST', Factory::getDate($rate->resources->core->reset)),
|
|
||||||
429
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->getApplication()->sendHeaders();
|
|
||||||
echo json_encode($response);
|
|
||||||
|
|
||||||
$this->getApplication()->close(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$testsModel = new TestsModel(null, Factory::getDbo());
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Sanity check, ensure there aren't any applied patches
|
|
||||||
if (count($testsModel->getAppliedPatches()) >= 1)
|
|
||||||
{
|
|
||||||
$response = new JsonResponse(new \Exception(Text::_('COM_PATCHTESTER_ERROR_APPLIED_PATCHES'), 500));
|
|
||||||
|
|
||||||
$this->getApplication()->sendHeaders();
|
|
||||||
echo json_encode($response);
|
|
||||||
|
|
||||||
$this->getApplication()->close(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (\Exception $e)
|
|
||||||
{
|
|
||||||
$response = new JsonResponse($e);
|
|
||||||
|
|
||||||
$this->getApplication()->sendHeaders();
|
|
||||||
echo json_encode($response);
|
|
||||||
|
|
||||||
$this->getApplication()->close(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're able to successfully pull data, prepare our environment
|
|
||||||
Factory::getSession()->set('com_patchtester_fetcher_page', 1);
|
|
||||||
|
|
||||||
$response = new JsonResponse(
|
|
||||||
array('complete' => false, 'header' => Text::_('COM_PATCHTESTER_FETCH_PROCESSING', true)),
|
|
||||||
Text::sprintf('COM_PATCHTESTER_FETCH_PAGE_NUMBER', 1),
|
|
||||||
false,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->getApplication()->sendHeaders();
|
|
||||||
echo json_encode($response);
|
|
||||||
|
|
||||||
$this->getApplication()->close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -11,7 +12,9 @@ namespace PatchTester\Field;
|
|||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\CMS\Form\Field\ListField;
|
use Joomla\CMS\Form\Field\ListField;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of available branches.
|
* List of available branches.
|
||||||
@ -21,34 +24,30 @@ defined('_JEXEC') or die;
|
|||||||
*/
|
*/
|
||||||
class BranchField extends ListField
|
class BranchField extends ListField
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Type of field
|
* Type of field
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
* @since 4.1.0
|
* @since 4.1.0
|
||||||
*/
|
*/
|
||||||
protected $type = 'Branch';
|
protected $type = 'Branch';
|
||||||
|
/**
|
||||||
/**
|
* Build a list of available branches.
|
||||||
* Build a list of available branches.
|
*
|
||||||
*
|
* @return array List of options
|
||||||
* @return array List of options
|
*
|
||||||
*
|
* @since 4.1.0
|
||||||
* @since 4.1.0
|
*/
|
||||||
*/
|
public function getOptions(): array
|
||||||
public function getOptions(): array
|
{
|
||||||
{
|
$db = Factory::getContainer()->get('DatabaseDriver');
|
||||||
$db = Factory::getContainer()->get('DatabaseDriver');
|
$query = $db->getQuery(true);
|
||||||
$query = $db->getQuery(true);
|
$query->select('DISTINCT(' . $db->quoteName('branch') . ') AS ' . $db->quoteName('text'))
|
||||||
|
->select($db->quoteName('branch', 'value'))
|
||||||
$query->select('DISTINCT(' . $db->quoteName('branch') . ') AS ' . $db->quoteName('text'))
|
->from('#__patchtester_pulls')
|
||||||
->select($db->quoteName('branch', 'value'))
|
->where($db->quoteName('branch') . ' != ' . $db->quote(''))
|
||||||
->from('#__patchtester_pulls')
|
->order($db->quoteName('branch') . ' ASC');
|
||||||
->where($db->quoteName('branch') . ' != ' . $db->quote(''))
|
$options = $db->setQuery($query)->loadAssocList();
|
||||||
->order($db->quoteName('branch') . ' ASC');
|
return array_merge(parent::getOptions(), $options);
|
||||||
|
}
|
||||||
$options = $db->setQuery($query)->loadAssocList();
|
|
||||||
|
|
||||||
return array_merge(parent::getOptions(), $options);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -11,7 +12,9 @@ namespace PatchTester\Field;
|
|||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\CMS\Form\Field\ListField;
|
use Joomla\CMS\Form\Field\ListField;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of available banks.
|
* List of available banks.
|
||||||
@ -21,33 +24,29 @@ defined('_JEXEC') or die;
|
|||||||
*/
|
*/
|
||||||
class LabelField extends ListField
|
class LabelField extends ListField
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Type of field
|
* Type of field
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
* @since 4.1.0
|
* @since 4.1.0
|
||||||
*/
|
*/
|
||||||
protected $type = 'Label';
|
protected $type = 'Label';
|
||||||
|
/**
|
||||||
/**
|
* Build a list of available fields.
|
||||||
* Build a list of available fields.
|
*
|
||||||
*
|
* @return array List of options
|
||||||
* @return array List of options
|
*
|
||||||
*
|
* @since 4.1.0
|
||||||
* @since 4.1.0
|
*/
|
||||||
*/
|
public function getOptions(): array
|
||||||
public function getOptions(): array
|
{
|
||||||
{
|
$db = Factory::getContainer()->get('DatabaseDriver');
|
||||||
$db = Factory::getContainer()->get('DatabaseDriver');
|
$query = $db->getQuery(true);
|
||||||
$query = $db->getQuery(true);
|
$query->select('DISTINCT(' . $db->quoteName('name') . ') AS ' . $db->quoteName('text'))
|
||||||
|
->select($db->quoteName('name', 'value'))
|
||||||
$query->select('DISTINCT(' . $db->quoteName('name') . ') AS ' . $db->quoteName('text'))
|
->from($db->quoteName('#__patchtester_pulls_labels'))
|
||||||
->select($db->quoteName('name', 'value'))
|
->order($db->quoteName('name') . ' ASC');
|
||||||
->from($db->quoteName('#__patchtester_pulls_labels'))
|
$options = $db->setQuery($query)->loadAssocList();
|
||||||
->order($db->quoteName('name') . ' ASC');
|
return array_merge(parent::getOptions(), $options);
|
||||||
|
}
|
||||||
$options = $db->setQuery($query)->loadAssocList();
|
|
||||||
|
|
||||||
return array_merge(parent::getOptions(), $options);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -17,40 +18,38 @@ use Joomla\CMS\Http\Response;
|
|||||||
*/
|
*/
|
||||||
class UnexpectedResponse extends \DomainException
|
class UnexpectedResponse extends \DomainException
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The Response object.
|
* The Response object.
|
||||||
*
|
*
|
||||||
* @var Response
|
* @var Response
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
private $response;
|
private $response;
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param Response $response The Response object.
|
||||||
|
* @param string $message The Exception message to throw.
|
||||||
|
* @param integer $code The Exception code.
|
||||||
|
* @param \Exception $previous The previous exception used for the exception chaining.
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public function __construct(Response $response, $message = '', $code = 0, \Exception $previous = null)
|
||||||
|
{
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
$this->response = $response;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Get the Response object.
|
||||||
*
|
*
|
||||||
* @param Response $response The Response object.
|
* @return Response
|
||||||
* @param string $message The Exception message to throw.
|
*
|
||||||
* @param integer $code The Exception code.
|
* @since 3.0.0
|
||||||
* @param \Exception $previous The previous exception used for the exception chaining.
|
*/
|
||||||
*
|
public function getResponse()
|
||||||
* @since 3.0.0
|
{
|
||||||
*/
|
return $this->response;
|
||||||
public function __construct(Response $response, $message = '', $code = 0, \Exception $previous = null)
|
}
|
||||||
{
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
|
|
||||||
$this->response = $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Response object.
|
|
||||||
*
|
|
||||||
* @return Response
|
|
||||||
*
|
|
||||||
* @since 3.0.0
|
|
||||||
*/
|
|
||||||
public function getResponse()
|
|
||||||
{
|
|
||||||
return $this->response;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -21,332 +22,304 @@ use Joomla\Registry\Registry;
|
|||||||
*/
|
*/
|
||||||
class GitHub
|
class GitHub
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Options for the connector.
|
* Options for the connector.
|
||||||
*
|
*
|
||||||
* @var Registry
|
* @var Registry
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
protected $options;
|
protected $options;
|
||||||
|
/**
|
||||||
|
* The HTTP client object to use in sending HTTP requests.
|
||||||
|
*
|
||||||
|
* @var Http
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
protected $client;
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param Registry $options Connector options.
|
||||||
|
* @param Http $client The HTTP client object.
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public function __construct(Registry $options = null, Http $client = null)
|
||||||
|
{
|
||||||
|
$this->options = $options ?: new Registry();
|
||||||
|
$this->client = $client ?: HttpFactory::getHttp($options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The HTTP client object to use in sending HTTP requests.
|
* Get the HTTP client for this connector.
|
||||||
*
|
*
|
||||||
* @var Http
|
* @return Http
|
||||||
* @since 3.0.0
|
*
|
||||||
*/
|
* @since 3.0.0
|
||||||
protected $client;
|
*/
|
||||||
|
public function getClient()
|
||||||
|
{
|
||||||
|
return $this->client;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Get the diff for a pull request.
|
||||||
*
|
*
|
||||||
* @param Registry $options Connector options.
|
* @param string $user The name of the owner of the GitHub repository.
|
||||||
* @param Http $client The HTTP client object.
|
* @param string $repo The name of the GitHub repository.
|
||||||
*
|
* @param integer $pullId The pull request number.
|
||||||
* @since 3.0.0
|
*
|
||||||
*/
|
* @return Response
|
||||||
public function __construct(Registry $options = null, Http $client = null)
|
*
|
||||||
{
|
* @since 3.0.0
|
||||||
$this->options = $options ?: new Registry;
|
*/
|
||||||
$this->client = $client ?: HttpFactory::getHttp($options);
|
public function getDiffForPullRequest($user, $repo, $pullId)
|
||||||
}
|
{
|
||||||
|
// Build the request path.
|
||||||
|
$path = "/repos/$user/$repo/pulls/" . (int) $pullId;
|
||||||
|
// Build the request headers.
|
||||||
|
$headers = array('Accept' => 'application/vnd.github.diff');
|
||||||
|
$prepared = $this->prepareRequest($path, 0, 0, $headers);
|
||||||
|
return $this->processResponse($this->client->get($prepared['url'], $prepared['headers']));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the HTTP client for this connector.
|
* Method to build and return a full request URL for the request.
|
||||||
*
|
*
|
||||||
* @return Http
|
* This method will add appropriate pagination details if necessary and also prepend the API url to have a complete URL for the request.
|
||||||
*
|
*
|
||||||
* @since 3.0.0
|
* @param string $path Path to process
|
||||||
*/
|
* @param integer $page Page to request
|
||||||
public function getClient()
|
* @param integer $limit Number of results to return per page
|
||||||
{
|
* @param array $headers The headers to send with the request
|
||||||
return $this->client;
|
*
|
||||||
}
|
* @return array Associative array containing the prepared URL and request headers
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
protected function prepareRequest(
|
||||||
|
$path,
|
||||||
|
$page = 0,
|
||||||
|
$limit = 0,
|
||||||
|
array $headers = array()
|
||||||
|
) {
|
||||||
|
$url = $this->fetchUrl($path, $page, $limit);
|
||||||
|
if ($token = $this->options->get('gh.token', false)) {
|
||||||
|
$headers['Authorization'] = "token $token";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
return array('url' => $url, 'headers' => $headers);
|
||||||
* Get the diff for a pull request.
|
}
|
||||||
*
|
|
||||||
* @param string $user The name of the owner of the GitHub repository.
|
|
||||||
* @param string $repo The name of the GitHub repository.
|
|
||||||
* @param integer $pullId The pull request number.
|
|
||||||
*
|
|
||||||
* @return Response
|
|
||||||
*
|
|
||||||
* @since 3.0.0
|
|
||||||
*/
|
|
||||||
public function getDiffForPullRequest($user, $repo, $pullId)
|
|
||||||
{
|
|
||||||
// Build the request path.
|
|
||||||
$path = "/repos/$user/$repo/pulls/" . (int) $pullId;
|
|
||||||
|
|
||||||
// Build the request headers.
|
/**
|
||||||
$headers = array('Accept' => 'application/vnd.github.diff');
|
* Build and return a full request URL.
|
||||||
|
*
|
||||||
|
* This method will add appropriate pagination details and basic authentication credentials if necessary
|
||||||
|
* and also prepend the API url to have a complete URL for the request.
|
||||||
|
*
|
||||||
|
* @param string $path URL to inflect
|
||||||
|
* @param integer $page Page to request
|
||||||
|
* @param integer $limit Number of results to return per page
|
||||||
|
*
|
||||||
|
* @return string The request URL.
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
protected function fetchUrl($path, $page = 0, $limit = 0)
|
||||||
|
{
|
||||||
|
// Get a new Uri object using the API URL and given path.
|
||||||
|
$uri = new Uri($this->options->get('api.url') . $path);
|
||||||
|
// If we have a defined page number add it to the JUri object.
|
||||||
|
if ($page > 0) {
|
||||||
|
$uri->setVar('page', (int) $page);
|
||||||
|
}
|
||||||
|
|
||||||
$prepared = $this->prepareRequest($path, 0, 0, $headers);
|
// If we have a defined items per page add it to the JUri object.
|
||||||
|
if ($limit > 0) {
|
||||||
|
$uri->setVar('per_page', (int) $limit);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->processResponse(
|
return (string) $uri;
|
||||||
$this->client->get($prepared['url'], $prepared['headers'])
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to build and return a full request URL for the request.
|
* Process the response and return it.
|
||||||
*
|
*
|
||||||
* This method will add appropriate pagination details if necessary and also prepend the API url to have a complete URL for the request.
|
* @param Response $response The response.
|
||||||
*
|
* @param integer $expectedCode The expected response code.
|
||||||
* @param string $path Path to process
|
*
|
||||||
* @param integer $page Page to request
|
* @return Response
|
||||||
* @param integer $limit Number of results to return per page
|
*
|
||||||
* @param array $headers The headers to send with the request
|
* @since 3.0.0
|
||||||
*
|
* @throws Exception\UnexpectedResponse
|
||||||
* @return array Associative array containing the prepared URL and request headers
|
*/
|
||||||
*
|
protected function processResponse(Response $response, $expectedCode = 200)
|
||||||
* @since 3.0.0
|
{
|
||||||
*/
|
// Validate the response code.
|
||||||
protected function prepareRequest($path, $page = 0, $limit = 0,
|
if ($response->code != $expectedCode) {
|
||||||
array $headers = array()
|
// Decode the error response and throw an exception.
|
||||||
) {
|
$body = json_decode($response->body);
|
||||||
$url = $this->fetchUrl($path, $page, $limit);
|
$error = isset($body->error) ? $body->error
|
||||||
|
: (isset($body->message) ? $body->message : 'Unknown Error');
|
||||||
|
|
||||||
if ($token = $this->options->get('gh.token', false))
|
throw new Exception\UnexpectedResponse(
|
||||||
{
|
$response,
|
||||||
$headers['Authorization'] = "token $token";
|
$error,
|
||||||
}
|
$response->code
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return array('url' => $url, 'headers' => $headers);
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build and return a full request URL.
|
* Get a file's contents from a repository.
|
||||||
*
|
*
|
||||||
* This method will add appropriate pagination details and basic authentication credentials if necessary
|
* @param string $user The name of the owner of the GitHub repository.
|
||||||
* and also prepend the API url to have a complete URL for the request.
|
* @param string $repo The name of the GitHub repository.
|
||||||
*
|
* @param string $path The content path.
|
||||||
* @param string $path URL to inflect
|
* @param string $ref The name of the commit/branch/tag. Default: the repository’s default branch (usually master)
|
||||||
* @param integer $page Page to request
|
*
|
||||||
* @param integer $limit Number of results to return per page
|
* @return Response
|
||||||
*
|
*
|
||||||
* @return string The request URL.
|
* @since 3.0.0
|
||||||
*
|
*/
|
||||||
* @since 3.0.0
|
public function getFileContents($user, $repo, $path, $ref = null)
|
||||||
*/
|
{
|
||||||
protected function fetchUrl($path, $page = 0, $limit = 0)
|
$path = "/repos/$user/$repo/contents/$path";
|
||||||
{
|
$prepared = $this->prepareRequest($path);
|
||||||
// Get a new Uri object using the API URL and given path.
|
if ($ref) {
|
||||||
$uri = new Uri($this->options->get('api.url') . $path);
|
$url = new Uri($prepared['url']);
|
||||||
|
$url->setVar('ref', $ref);
|
||||||
|
$prepared['url'] = (string) $url;
|
||||||
|
}
|
||||||
|
|
||||||
// If we have a defined page number add it to the JUri object.
|
return $this->processResponse($this->client->get($prepared['url'], $prepared['headers']));
|
||||||
if ($page > 0)
|
}
|
||||||
{
|
|
||||||
$uri->setVar('page', (int) $page);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a defined items per page add it to the JUri object.
|
/**
|
||||||
if ($limit > 0)
|
* Get the list of modified files for a pull request.
|
||||||
{
|
*
|
||||||
$uri->setVar('per_page', (int) $limit);
|
* @param string $user The name of the owner of the GitHub repository.
|
||||||
}
|
* @param string $repo The name of the GitHub repository.
|
||||||
|
* @param integer $pullId The pull request number.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public function getFilesForPullRequest($user, $repo, $pullId, $page = 1)
|
||||||
|
{
|
||||||
|
// Build the request path.
|
||||||
|
$path = "/repos/$user/$repo/pulls/" . (int) $pullId . '/files?page=' . $page;
|
||||||
|
$prepared = $this->prepareRequest($path);
|
||||||
|
return $this->processResponse($this->client->get($prepared['url'], $prepared['headers']));
|
||||||
|
}
|
||||||
|
|
||||||
return (string) $uri;
|
/**
|
||||||
}
|
* Get a list of the open issues for a repository.
|
||||||
|
*
|
||||||
|
* @param string $user The name of the owner of the GitHub repository.
|
||||||
|
* @param string $repo The name of the GitHub repository.
|
||||||
|
* @param integer $page The page number from which to get items.
|
||||||
|
* @param integer $limit The number of items on a page.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public function getOpenIssues($user, $repo, $page = 0, $limit = 0)
|
||||||
|
{
|
||||||
|
$prepared = $this->prepareRequest(
|
||||||
|
"/repos/$user/$repo/issues",
|
||||||
|
$page,
|
||||||
|
$limit
|
||||||
|
);
|
||||||
|
return $this->processResponse($this->client->get($prepared['url'], $prepared['headers']));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the response and return it.
|
* Get a list of the open pull requests for a repository.
|
||||||
*
|
*
|
||||||
* @param Response $response The response.
|
* @param string $user The name of the owner of the GitHub repository.
|
||||||
* @param integer $expectedCode The expected response code.
|
* @param string $repo The name of the GitHub repository.
|
||||||
*
|
* @param integer $page The page number from which to get items.
|
||||||
* @return Response
|
* @param integer $limit The number of items on a page.
|
||||||
*
|
*
|
||||||
* @since 3.0.0
|
* @return Response
|
||||||
* @throws Exception\UnexpectedResponse
|
*
|
||||||
*/
|
* @since 3.0.0
|
||||||
protected function processResponse(Response $response, $expectedCode = 200)
|
*/
|
||||||
{
|
public function getOpenPulls($user, $repo, $page = 0, $limit = 0)
|
||||||
// Validate the response code.
|
{
|
||||||
if ($response->code != $expectedCode)
|
$prepared = $this->prepareRequest(
|
||||||
{
|
"/repos/$user/$repo/pulls",
|
||||||
// Decode the error response and throw an exception.
|
$page,
|
||||||
$body = json_decode($response->body);
|
$limit
|
||||||
$error = isset($body->error) ? $body->error
|
);
|
||||||
: (isset($body->message) ? $body->message : 'Unknown Error');
|
return $this->processResponse($this->client->get($prepared['url'], $prepared['headers']));
|
||||||
|
}
|
||||||
|
|
||||||
throw new Exception\UnexpectedResponse(
|
/**
|
||||||
$response, $error, $response->code
|
* Get an option from the connector.
|
||||||
);
|
*
|
||||||
}
|
* @param string $key The name of the option to get.
|
||||||
|
* @param mixed $default The default value if the option is not set.
|
||||||
|
*
|
||||||
|
* @return mixed The option value.
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public function getOption($key, $default = null)
|
||||||
|
{
|
||||||
|
return $this->options->get($key, $default);
|
||||||
|
}
|
||||||
|
|
||||||
return $response;
|
/**
|
||||||
}
|
* Get a single pull request.
|
||||||
|
*
|
||||||
|
* @param string $user The name of the owner of the GitHub repository.
|
||||||
|
* @param string $repo The name of the GitHub repository.
|
||||||
|
* @param integer $pullId The pull request number.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public function getPullRequest($user, $repo, $pullId)
|
||||||
|
{
|
||||||
|
// Build the request path.
|
||||||
|
$path = "/repos/$user/$repo/pulls/" . (int) $pullId;
|
||||||
|
$prepared = $this->prepareRequest($path);
|
||||||
|
return $this->processResponse($this->client->get($prepared['url'], $prepared['headers']));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a file's contents from a repository.
|
* Get the rate limit for the authenticated user.
|
||||||
*
|
*
|
||||||
* @param string $user The name of the owner of the GitHub repository.
|
* @return Response
|
||||||
* @param string $repo The name of the GitHub repository.
|
*
|
||||||
* @param string $path The content path.
|
* @since 3.0.0
|
||||||
* @param string $ref The name of the commit/branch/tag. Default: the repository’s default branch (usually master)
|
*/
|
||||||
*
|
public function getRateLimit()
|
||||||
* @return Response
|
{
|
||||||
*
|
$prepared = $this->prepareRequest('/rate_limit');
|
||||||
* @since 3.0.0
|
return $this->processResponse($this->client->get($prepared['url'], $prepared['headers']));
|
||||||
*/
|
}
|
||||||
public function getFileContents($user, $repo, $path, $ref = null)
|
|
||||||
{
|
|
||||||
$path = "/repos/$user/$repo/contents/$path";
|
|
||||||
|
|
||||||
$prepared = $this->prepareRequest($path);
|
/**
|
||||||
|
* Set an option for the connector.
|
||||||
if ($ref)
|
*
|
||||||
{
|
* @param string $key The name of the option to set.
|
||||||
$url = new Uri($prepared['url']);
|
* @param mixed $value The option value to set.
|
||||||
$url->setVar('ref', $ref);
|
*
|
||||||
|
* @return $this
|
||||||
$prepared['url'] = (string) $url;
|
*
|
||||||
}
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
return $this->processResponse(
|
public function setOption($key, $value)
|
||||||
$this->client->get($prepared['url'], $prepared['headers'])
|
{
|
||||||
);
|
$this->options->set($key, $value);
|
||||||
}
|
return $this;
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Get the list of modified files for a pull request.
|
|
||||||
*
|
|
||||||
* @param string $user The name of the owner of the GitHub repository.
|
|
||||||
* @param string $repo The name of the GitHub repository.
|
|
||||||
* @param integer $pullId The pull request number.
|
|
||||||
*
|
|
||||||
* @return Response
|
|
||||||
*
|
|
||||||
* @since 3.0.0
|
|
||||||
*/
|
|
||||||
public function getFilesForPullRequest($user, $repo, $pullId, $page = 1)
|
|
||||||
{
|
|
||||||
// Build the request path.
|
|
||||||
$path = "/repos/$user/$repo/pulls/" . (int) $pullId . '/files?page=' . $page;
|
|
||||||
|
|
||||||
$prepared = $this->prepareRequest($path);
|
|
||||||
|
|
||||||
return $this->processResponse(
|
|
||||||
$this->client->get($prepared['url'], $prepared['headers'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of the open issues for a repository.
|
|
||||||
*
|
|
||||||
* @param string $user The name of the owner of the GitHub repository.
|
|
||||||
* @param string $repo The name of the GitHub repository.
|
|
||||||
* @param integer $page The page number from which to get items.
|
|
||||||
* @param integer $limit The number of items on a page.
|
|
||||||
*
|
|
||||||
* @return Response
|
|
||||||
*
|
|
||||||
* @since 3.0.0
|
|
||||||
*/
|
|
||||||
public function getOpenIssues($user, $repo, $page = 0, $limit = 0)
|
|
||||||
{
|
|
||||||
$prepared = $this->prepareRequest(
|
|
||||||
"/repos/$user/$repo/issues", $page, $limit
|
|
||||||
);
|
|
||||||
|
|
||||||
return $this->processResponse(
|
|
||||||
$this->client->get($prepared['url'], $prepared['headers'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of the open pull requests for a repository.
|
|
||||||
*
|
|
||||||
* @param string $user The name of the owner of the GitHub repository.
|
|
||||||
* @param string $repo The name of the GitHub repository.
|
|
||||||
* @param integer $page The page number from which to get items.
|
|
||||||
* @param integer $limit The number of items on a page.
|
|
||||||
*
|
|
||||||
* @return Response
|
|
||||||
*
|
|
||||||
* @since 3.0.0
|
|
||||||
*/
|
|
||||||
public function getOpenPulls($user, $repo, $page = 0, $limit = 0)
|
|
||||||
{
|
|
||||||
$prepared = $this->prepareRequest(
|
|
||||||
"/repos/$user/$repo/pulls", $page, $limit
|
|
||||||
);
|
|
||||||
|
|
||||||
return $this->processResponse(
|
|
||||||
$this->client->get($prepared['url'], $prepared['headers'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an option from the connector.
|
|
||||||
*
|
|
||||||
* @param string $key The name of the option to get.
|
|
||||||
* @param mixed $default The default value if the option is not set.
|
|
||||||
*
|
|
||||||
* @return mixed The option value.
|
|
||||||
*
|
|
||||||
* @since 3.0.0
|
|
||||||
*/
|
|
||||||
public function getOption($key, $default = null)
|
|
||||||
{
|
|
||||||
return $this->options->get($key, $default);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a single pull request.
|
|
||||||
*
|
|
||||||
* @param string $user The name of the owner of the GitHub repository.
|
|
||||||
* @param string $repo The name of the GitHub repository.
|
|
||||||
* @param integer $pullId The pull request number.
|
|
||||||
*
|
|
||||||
* @return Response
|
|
||||||
*
|
|
||||||
* @since 3.0.0
|
|
||||||
*/
|
|
||||||
public function getPullRequest($user, $repo, $pullId)
|
|
||||||
{
|
|
||||||
// Build the request path.
|
|
||||||
$path = "/repos/$user/$repo/pulls/" . (int) $pullId;
|
|
||||||
|
|
||||||
$prepared = $this->prepareRequest($path);
|
|
||||||
|
|
||||||
return $this->processResponse(
|
|
||||||
$this->client->get($prepared['url'], $prepared['headers'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the rate limit for the authenticated user.
|
|
||||||
*
|
|
||||||
* @return Response
|
|
||||||
*
|
|
||||||
* @since 3.0.0
|
|
||||||
*/
|
|
||||||
public function getRateLimit()
|
|
||||||
{
|
|
||||||
$prepared = $this->prepareRequest('/rate_limit');
|
|
||||||
|
|
||||||
return $this->processResponse(
|
|
||||||
$this->client->get($prepared['url'], $prepared['headers'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set an option for the connector.
|
|
||||||
*
|
|
||||||
* @param string $key The name of the option to set.
|
|
||||||
* @param mixed $value The option value to set.
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*
|
|
||||||
* @since 3.0.0
|
|
||||||
*/
|
|
||||||
public function setOption($key, $value)
|
|
||||||
{
|
|
||||||
$this->options->set($key, $value);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -14,6 +15,10 @@ use Joomla\CMS\Language\Text;
|
|||||||
use Joomla\Registry\Registry;
|
use Joomla\Registry\Registry;
|
||||||
use PatchTester\GitHub\GitHub;
|
use PatchTester\GitHub\GitHub;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for the patch tester component
|
* Helper class for the patch tester component
|
||||||
*
|
*
|
||||||
@ -21,69 +26,55 @@ use PatchTester\GitHub\GitHub;
|
|||||||
*/
|
*/
|
||||||
abstract class Helper
|
abstract class Helper
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Initializes the GitHub object
|
* Initializes the GitHub object
|
||||||
*
|
*
|
||||||
* @return GitHub
|
* @return GitHub
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public static function initializeGithub()
|
public static function initializeGithub()
|
||||||
{
|
{
|
||||||
$params = ComponentHelper::getParams('com_patchtester');
|
$params = ComponentHelper::getParams('com_patchtester');
|
||||||
|
$options = new Registry();
|
||||||
|
// Set a user agent for the request
|
||||||
|
$options->set('userAgent', 'PatchTester/3.0');
|
||||||
|
// Set the default timeout to 120 seconds
|
||||||
|
$options->set('timeout', 120);
|
||||||
|
// Set the API URL
|
||||||
|
$options->set('api.url', 'https://api.github.com');
|
||||||
|
// If an API token is set in the params, use it for authentication
|
||||||
|
if ($params->get('gh_token', '')) {
|
||||||
|
$options->set('headers', ['Authorization' => 'token ' . $params->get('gh_token', '')]);
|
||||||
|
} else {
|
||||||
|
// Display a message about the lowered API limit without credentials
|
||||||
|
Factory::getApplication()->enqueueMessage(Text::_('COM_PATCHTESTER_NO_CREDENTIALS'), 'notice');
|
||||||
|
}
|
||||||
|
|
||||||
$options = new Registry;
|
return new GitHub($options);
|
||||||
|
}
|
||||||
|
|
||||||
// Set a user agent for the request
|
/**
|
||||||
$options->set('userAgent', 'PatchTester/3.0');
|
* Initializes the CI Settings
|
||||||
|
*
|
||||||
// Set the default timeout to 120 seconds
|
* @return Registry
|
||||||
$options->set('timeout', 120);
|
*
|
||||||
|
* @since 3.0
|
||||||
// Set the API URL
|
*/
|
||||||
$options->set('api.url', 'https://api.github.com');
|
public static function initializeCISettings()
|
||||||
|
{
|
||||||
// If an API token is set in the params, use it for authentication
|
$params = ComponentHelper::getParams('com_patchtester');
|
||||||
if ($params->get('gh_token', ''))
|
$options = new Registry();
|
||||||
{
|
// Set CI server address for the request
|
||||||
$options->set('headers', ['Authorization' => 'token ' . $params->get('gh_token', '')]);
|
$options->set('server.url', $params->get('ci_server', 'https://ci.joomla.org:444'));
|
||||||
}
|
// Set name of the zip archive
|
||||||
// Display a message about the lowered API limit without credentials
|
$options->set('zip.name', 'build.zip');
|
||||||
else
|
$options->set('zip.log.name', 'deleted_files.log');
|
||||||
{
|
// Set temp archive for extracting and downloading files
|
||||||
Factory::getApplication()->enqueueMessage(Text::_('COM_PATCHTESTER_NO_CREDENTIALS'), 'notice');
|
$options->set('folder.temp', Factory::getConfig()->get('tmp_path'));
|
||||||
}
|
$options->set('folder.backups', JPATH_COMPONENT . '/backups');
|
||||||
|
// Set full url for addressing the file
|
||||||
return new GitHub($options);
|
$options->set('zip.url', $options->get('server.url') . '/artifacts/joomla/joomla-cms/4.0-dev/%s/patchtester/' . $options->get('zip.name'));
|
||||||
}
|
return $options;
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Initializes the CI Settings
|
|
||||||
*
|
|
||||||
* @return Registry
|
|
||||||
*
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
public static function initializeCISettings()
|
|
||||||
{
|
|
||||||
$params = ComponentHelper::getParams('com_patchtester');
|
|
||||||
|
|
||||||
$options = new Registry;
|
|
||||||
|
|
||||||
// Set CI server address for the request
|
|
||||||
$options->set('server.url', $params->get('ci_server', 'https://ci.joomla.org:444'));
|
|
||||||
|
|
||||||
// Set name of the zip archive
|
|
||||||
$options->set('zip.name', 'build.zip');
|
|
||||||
$options->set('zip.log.name', 'deleted_files.log');
|
|
||||||
|
|
||||||
// Set temp archive for extracting and downloading files
|
|
||||||
$options->set('folder.temp', Factory::getConfig()->get('tmp_path'));
|
|
||||||
$options->set('folder.backups', JPATH_COMPONENT . '/backups');
|
|
||||||
|
|
||||||
// Set full url for addressing the file
|
|
||||||
$options->set('zip.url', $options->get('server.url') . '/artifacts/joomla/joomla-cms/4.0-dev/%s/patchtester/' . $options->get('zip.name'));
|
|
||||||
|
|
||||||
return $options;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -18,85 +19,83 @@ use Joomla\Registry\Registry;
|
|||||||
*/
|
*/
|
||||||
abstract class AbstractModel
|
abstract class AbstractModel
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The database driver.
|
* The database driver.
|
||||||
*
|
*
|
||||||
* @var \JDatabaseDriver
|
* @var \JDatabaseDriver
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
protected $db;
|
protected $db;
|
||||||
|
/**
|
||||||
|
* The model state.
|
||||||
|
*
|
||||||
|
* @var Registry
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
protected $state;
|
||||||
|
/**
|
||||||
|
* Instantiate the model.
|
||||||
|
*
|
||||||
|
* @param Registry $state The model state.
|
||||||
|
* @param \JDatabaseDriver $db The database adpater.
|
||||||
|
*
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
public function __construct(Registry $state = null, \JDatabaseDriver $db = null)
|
||||||
|
{
|
||||||
|
$this->state = $state ?: new Registry();
|
||||||
|
$this->db = $db ?: Factory::getDbo();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The model state.
|
* Get the database driver.
|
||||||
*
|
*
|
||||||
* @var Registry
|
* @return \JDatabaseDriver
|
||||||
* @since 4.0.0
|
*
|
||||||
*/
|
* @since 4.0.0
|
||||||
protected $state;
|
*/
|
||||||
|
public function getDb()
|
||||||
|
{
|
||||||
|
return $this->db;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiate the model.
|
* Get the model state.
|
||||||
*
|
*
|
||||||
* @param Registry $state The model state.
|
* @return Registry
|
||||||
* @param \JDatabaseDriver $db The database adpater.
|
*
|
||||||
*
|
* @since 4.0.0
|
||||||
* @since 4.0.0
|
*/
|
||||||
*/
|
public function getState()
|
||||||
public function __construct(Registry $state = null, \JDatabaseDriver $db = null)
|
{
|
||||||
{
|
return $this->state;
|
||||||
$this->state = $state ?: new Registry;
|
}
|
||||||
$this->db = $db ?: Factory::getDbo();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the database driver.
|
* Set the database driver.
|
||||||
*
|
*
|
||||||
* @return \JDatabaseDriver
|
* @param \JDatabaseDriver $db The database driver.
|
||||||
*
|
*
|
||||||
* @since 4.0.0
|
* @return void
|
||||||
*/
|
*
|
||||||
public function getDb()
|
* @since 4.0.0
|
||||||
{
|
*/
|
||||||
return $this->db;
|
public function setDb(\JDatabaseDriver $db)
|
||||||
}
|
{
|
||||||
|
$this->db = $db;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the model state.
|
* Set the model state.
|
||||||
*
|
*
|
||||||
* @return Registry
|
* @param Registry $state The state object.
|
||||||
*
|
*
|
||||||
* @since 4.0.0
|
* @return void
|
||||||
*/
|
*
|
||||||
public function getState()
|
* @since 4.0.0
|
||||||
{
|
*/
|
||||||
return $this->state;
|
public function setState(Registry $state)
|
||||||
}
|
{
|
||||||
|
$this->state = $state;
|
||||||
/**
|
}
|
||||||
* Set the database driver.
|
|
||||||
*
|
|
||||||
* @param \JDatabaseDriver $db The database driver.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @since 4.0.0
|
|
||||||
*/
|
|
||||||
public function setDb(\JDatabaseDriver $db)
|
|
||||||
{
|
|
||||||
$this->db = $db;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the model state.
|
|
||||||
*
|
|
||||||
* @param Registry $state The state object.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @since 4.0.0
|
|
||||||
*/
|
|
||||||
public function setState(Registry $state)
|
|
||||||
{
|
|
||||||
$this->state = $state;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -8,6 +9,10 @@
|
|||||||
|
|
||||||
namespace PatchTester\Model;
|
namespace PatchTester\Model;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model class for the fetch modal view
|
* Model class for the fetch modal view
|
||||||
*
|
*
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -15,6 +16,10 @@ use Joomla\CMS\MVC\Model\ListModel;
|
|||||||
use PatchTester\GitHub\Exception\UnexpectedResponse;
|
use PatchTester\GitHub\Exception\UnexpectedResponse;
|
||||||
use PatchTester\Helper;
|
use PatchTester\Helper;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model class for the pulls list view
|
* Model class for the pulls list view
|
||||||
*
|
*
|
||||||
@ -22,533 +27,403 @@ use PatchTester\Helper;
|
|||||||
*/
|
*/
|
||||||
class PullsModel extends ListModel
|
class PullsModel extends ListModel
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The object context
|
* The object context
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
protected $context;
|
protected $context;
|
||||||
|
/**
|
||||||
/**
|
* Array of fields the list can be sorted on
|
||||||
* Array of fields the list can be sorted on
|
*
|
||||||
*
|
* @var array
|
||||||
* @var array
|
* @since 2.0
|
||||||
* @since 2.0
|
*/
|
||||||
*/
|
protected $sortFields = array('pulls.pull_id', 'pulls.title');
|
||||||
protected $sortFields = array('pulls.pull_id', 'pulls.title');
|
/**
|
||||||
|
* Constructor.
|
||||||
/**
|
*
|
||||||
* Constructor.
|
* @param array $config An optional associative array of configuration settings.
|
||||||
*
|
*
|
||||||
* @param array $config An optional associative array of configuration settings.
|
* @since 4.0.0
|
||||||
*
|
* @throws Exception
|
||||||
* @since 4.0.0
|
*
|
||||||
* @throws Exception
|
*/
|
||||||
*
|
public function __construct($config = [])
|
||||||
*/
|
{
|
||||||
public function __construct($config = [])
|
$config = [];
|
||||||
{
|
if (empty($config['filter_fields'])) {
|
||||||
$config = [];
|
$config['filter_fields'] = [
|
||||||
|
'applied',
|
||||||
if (empty($config['filter_fields']))
|
'rtc',
|
||||||
{
|
'npm',
|
||||||
$config['filter_fields'] = [
|
'draft',
|
||||||
'applied',
|
'label',
|
||||||
'rtc',
|
'branch',
|
||||||
'npm',
|
];
|
||||||
'draft',
|
}
|
||||||
'label',
|
|
||||||
'branch',
|
parent::__construct($config);
|
||||||
];
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
parent::__construct($config);
|
* Method to get an array of data items.
|
||||||
}
|
*
|
||||||
|
* @return mixed An array of data items on success, false on failure.
|
||||||
/**
|
*
|
||||||
* Method to get an array of data items.
|
* @since 2.0
|
||||||
*
|
*/
|
||||||
* @return mixed An array of data items on success, false on failure.
|
public function getItems()
|
||||||
*
|
{
|
||||||
* @since 2.0
|
$store = $this->getStoreId();
|
||||||
*/
|
if (isset($this->cache[$store])) {
|
||||||
public function getItems()
|
return $this->cache[$store];
|
||||||
{
|
}
|
||||||
$store = $this->getStoreId();
|
|
||||||
|
$items = $this->getList(
|
||||||
if (isset($this->cache[$store]))
|
$this->getListQueryCache(),
|
||||||
{
|
$this->getStart(),
|
||||||
return $this->cache[$store];
|
$this->getState()->get('list.limit')
|
||||||
}
|
);
|
||||||
|
$db = $this->getDbo();
|
||||||
$items = $this->getList(
|
$query = $db->getQuery(true)
|
||||||
$this->getListQueryCache(), $this->getStart(),
|
->select($db->quoteName(['name', 'color']))
|
||||||
$this->getState()->get('list.limit')
|
->from($db->quoteName('#__patchtester_pulls_labels'));
|
||||||
);
|
array_walk($items, static function ($item) use ($db, $query) {
|
||||||
|
|
||||||
$db = $this->getDbo();
|
$query->clear('where');
|
||||||
$query = $db->getQuery(true)
|
$query->where($db->quoteName('pull_id') . ' = ' . $item->pull_id);
|
||||||
->select($db->quoteName(['name', 'color']))
|
$db->setQuery($query);
|
||||||
->from($db->quoteName('#__patchtester_pulls_labels'));
|
$item->labels = $db->loadObjectList();
|
||||||
|
});
|
||||||
array_walk(
|
$this->cache[$store] = $items;
|
||||||
$items,
|
return $this->cache[$store];
|
||||||
static function ($item) use ($db, $query) {
|
}
|
||||||
$query->clear('where');
|
|
||||||
$query->where(
|
/**
|
||||||
$db->quoteName('pull_id') . ' = ' . $item->pull_id
|
* Method to get a store id based on the model configuration state.
|
||||||
);
|
*
|
||||||
$db->setQuery($query);
|
* This is necessary because the model is used by the component and
|
||||||
|
* different modules that might need different sets of data or different
|
||||||
$item->labels = $db->loadObjectList();
|
* ordering requirements.
|
||||||
}
|
*
|
||||||
);
|
* @param string $id An identifier string to generate the store id.
|
||||||
|
*
|
||||||
$this->cache[$store] = $items;
|
* @return string A store id.
|
||||||
|
*
|
||||||
return $this->cache[$store];
|
* @since 2.0
|
||||||
}
|
*/
|
||||||
|
protected function getStoreId($id = '')
|
||||||
/**
|
{
|
||||||
* Method to get a store id based on the model configuration state.
|
// Add the list state to the store id.
|
||||||
*
|
$id .= ':' . $this->getState()->get('list.start');
|
||||||
* This is necessary because the model is used by the component and
|
$id .= ':' . $this->getState()->get('list.limit');
|
||||||
* different modules that might need different sets of data or different
|
$id .= ':' . $this->getState()->get('list.ordering');
|
||||||
* ordering requirements.
|
$id .= ':' . $this->getState()->get('list.direction');
|
||||||
*
|
return md5($this->context . ':' . $id);
|
||||||
* @param string $id An identifier string to generate the store id.
|
}
|
||||||
*
|
|
||||||
* @return string A store id.
|
/**
|
||||||
*
|
* Gets an array of objects from the results of database query.
|
||||||
* @since 2.0
|
*
|
||||||
*/
|
* @param \JDatabaseQuery|string $query The query.
|
||||||
protected function getStoreId($id = '')
|
* @param integer $limitstart Offset.
|
||||||
{
|
* @param integer $limit The number of records.
|
||||||
// Add the list state to the store id.
|
*
|
||||||
$id .= ':' . $this->getState()->get('list.start');
|
* @return array An array of results.
|
||||||
$id .= ':' . $this->getState()->get('list.limit');
|
*
|
||||||
$id .= ':' . $this->getState()->get('list.ordering');
|
* @since 2.0
|
||||||
$id .= ':' . $this->getState()->get('list.direction');
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
return md5($this->context . ':' . $id);
|
protected function getList($query, $limitstart = 0, $limit = 0)
|
||||||
}
|
{
|
||||||
|
return $this->getDbo()->setQuery($query, $limitstart, $limit)
|
||||||
/**
|
->loadObjectList();
|
||||||
* Gets an array of objects from the results of database query.
|
}
|
||||||
*
|
|
||||||
* @param \JDatabaseQuery|string $query The query.
|
/**
|
||||||
* @param integer $limitstart Offset.
|
* Method to cache the last query constructed.
|
||||||
* @param integer $limit The number of records.
|
*
|
||||||
*
|
* This method ensures that the query is constructed only once for a given state of the model.
|
||||||
* @return array An array of results.
|
*
|
||||||
*
|
* @return \JDatabaseQuery A JDatabaseQuery object
|
||||||
* @since 2.0
|
*
|
||||||
* @throws RuntimeException
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
protected function getList($query, $limitstart = 0, $limit = 0)
|
protected function getListQueryCache()
|
||||||
{
|
{
|
||||||
return $this->getDbo()->setQuery($query, $limitstart, $limit)
|
// Capture the last store id used.
|
||||||
->loadObjectList();
|
static $lastStoreId;
|
||||||
}
|
// Compute the current store id.
|
||||||
|
$currentStoreId = $this->getStoreId();
|
||||||
/**
|
// If the last store id is different from the current, refresh the query.
|
||||||
* Method to cache the last query constructed.
|
if ($lastStoreId != $currentStoreId || empty($this->query)) {
|
||||||
*
|
$lastStoreId = $currentStoreId;
|
||||||
* This method ensures that the query is constructed only once for a given state of the model.
|
$this->query = $this->getListQuery();
|
||||||
*
|
}
|
||||||
* @return \JDatabaseQuery A JDatabaseQuery object
|
|
||||||
*
|
return $this->query;
|
||||||
* @since 2.0
|
}
|
||||||
*/
|
|
||||||
protected function getListQueryCache()
|
/**
|
||||||
{
|
* Method to get a JDatabaseQuery object for retrieving the data set from a database.
|
||||||
// Capture the last store id used.
|
*
|
||||||
static $lastStoreId;
|
* @return \JDatabaseQuery A JDatabaseQuery object to retrieve the data set.
|
||||||
|
*
|
||||||
// Compute the current store id.
|
* @since 2.0
|
||||||
$currentStoreId = $this->getStoreId();
|
*/
|
||||||
|
protected function getListQuery()
|
||||||
// If the last store id is different from the current, refresh the query.
|
{
|
||||||
if ($lastStoreId != $currentStoreId || empty($this->query))
|
$db = $this->getDbo();
|
||||||
{
|
$query = $db->getQuery(true);
|
||||||
$lastStoreId = $currentStoreId;
|
$labelQuery = $db->getQuery(true);
|
||||||
$this->query = $this->getListQuery();
|
$query->select('pulls.*')
|
||||||
}
|
->select($db->quoteName('tests.id', 'applied'))
|
||||||
|
->from($db->quoteName('#__patchtester_pulls', 'pulls'))
|
||||||
return $this->query;
|
->leftJoin($db->quoteName('#__patchtester_tests', 'tests')
|
||||||
}
|
. ' ON ' . $db->quoteName('tests.pull_id') . ' = '
|
||||||
|
. $db->quoteName('pulls.pull_id'));
|
||||||
/**
|
$search = $this->getState()->get('filter.search');
|
||||||
* Method to get a JDatabaseQuery object for retrieving the data set from a database.
|
|
||||||
*
|
if (!empty($search)) {
|
||||||
* @return \JDatabaseQuery A JDatabaseQuery object to retrieve the data set.
|
if (stripos($search, 'id:') === 0) {
|
||||||
*
|
$query->where($db->quoteName('pulls.pull_id') . ' = ' . (int) substr(
|
||||||
* @since 2.0
|
$search,
|
||||||
*/
|
3
|
||||||
protected function getListQuery()
|
));
|
||||||
{
|
} elseif (is_numeric($search)) {
|
||||||
$db = $this->getDbo();
|
$query->where($db->quoteName('pulls.pull_id') . ' = ' . (int) $search);
|
||||||
$query = $db->getQuery(true);
|
} else {
|
||||||
$labelQuery = $db->getQuery(true);
|
$query->where('(' . $db->quoteName('pulls.title') . ' LIKE ' . $db->quote('%' . $db->escape($search, true) . '%') . ')');
|
||||||
|
}
|
||||||
$query->select('pulls.*')
|
}
|
||||||
->select($db->quoteName('tests.id', 'applied'))
|
|
||||||
->from($db->quoteName('#__patchtester_pulls', 'pulls'))
|
$applied = $this->getState()->get('filter.applied');
|
||||||
->leftJoin(
|
if (!empty($applied)) {
|
||||||
$db->quoteName('#__patchtester_tests', 'tests')
|
// Not applied patches have a NULL value, so build our value part of the query based on this
|
||||||
. ' ON ' . $db->quoteName('tests.pull_id') . ' = '
|
$value = $applied === 'no' ? ' IS NULL' : ' = 1';
|
||||||
. $db->quoteName('pulls.pull_id')
|
$query->where($db->quoteName('applied') . $value);
|
||||||
);
|
}
|
||||||
|
|
||||||
$search = $this->getState()->get('filter.search');
|
$branch = $this->getState()->get('filter.branch');
|
||||||
|
if (!empty($branch)) {
|
||||||
if (!empty($search))
|
$query->where($db->quoteName('pulls.branch') . ' IN (' . implode(',', $db->quote($branch)) . ')');
|
||||||
{
|
}
|
||||||
if (stripos($search, 'id:') === 0)
|
|
||||||
{
|
$applied = $this->getState()->get('filter.rtc');
|
||||||
$query->where(
|
if (!empty($applied)) {
|
||||||
$db->quoteName('pulls.pull_id') . ' = ' . (int) substr(
|
// Not applied patches have a NULL value, so build our value part of the query based on this
|
||||||
$search, 3
|
$value = $applied === 'no' ? '0' : '1';
|
||||||
)
|
$query->where($db->quoteName('pulls.is_rtc') . ' = ' . $value);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
elseif (is_numeric($search))
|
$npm = $this->getState()->get('filter.npm');
|
||||||
{
|
if (!empty($npm)) {
|
||||||
$query->where(
|
// Not applied patches have a NULL value, so build our value part of the query based on this
|
||||||
$db->quoteName('pulls.pull_id') . ' = ' . (int) $search
|
$value = $npm === 'no' ? '0' : '1';
|
||||||
);
|
$query->where($db->quoteName('pulls.is_npm') . ' = ' . $value);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
$draft = $this->getState()->get('filter.draft');
|
||||||
$query->where(
|
if (!empty($draft)) {
|
||||||
'(' . $db->quoteName('pulls.title') . ' LIKE ' . $db->quote(
|
// Not applied patches have a NULL value, so build our value part of the query based on this
|
||||||
'%' . $db->escape($search, true) . '%'
|
$value = $draft === 'no' ? '0' : '1';
|
||||||
) . ')'
|
$query->where($db->quoteName('pulls.is_draft') . ' = ' . $value);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
}
|
$labels = $this->getState()->get('filter.label');
|
||||||
|
|
||||||
$applied = $this->getState()->get('filter.applied');
|
if (!empty($labels) && $labels[0] !== '') {
|
||||||
|
$labelQuery
|
||||||
if (!empty($applied))
|
->select($db->quoteName('pulls_labels.pull_id'))
|
||||||
{
|
->select('COUNT(' . $db->quoteName('pulls_labels.name') . ') AS '
|
||||||
// Not applied patches have a NULL value, so build our value part of the query based on this
|
. $db->quoteName('labelCount'))
|
||||||
$value = $applied === 'no' ? ' IS NULL' : ' = 1';
|
->from($db->quoteName(
|
||||||
|
'#__patchtester_pulls_labels',
|
||||||
$query->where($db->quoteName('applied') . $value);
|
'pulls_labels'
|
||||||
}
|
))
|
||||||
|
->where($db->quoteName('pulls_labels.name') . ' IN (' . implode(
|
||||||
$branch = $this->getState()->get('filter.branch');
|
',',
|
||||||
|
$db->quote($labels)
|
||||||
if (!empty($branch))
|
) . ')')
|
||||||
{
|
->group($db->quoteName('pulls_labels.pull_id'));
|
||||||
$query->where(
|
$query->leftJoin('(' . $labelQuery->__toString() . ') AS ' . $db->quoteName('pulls_labels')
|
||||||
$db->quoteName('pulls.branch') . ' IN (' . implode(',', $db->quote($branch)) . ')'
|
. ' ON ' . $db->quoteName('pulls_labels.pull_id') . ' = '
|
||||||
);
|
. $db->quoteName('pulls.pull_id'))
|
||||||
}
|
->where($db->quoteName('pulls_labels.labelCount') . ' = ' . count($labels));
|
||||||
|
}
|
||||||
$applied = $this->getState()->get('filter.rtc');
|
|
||||||
|
$ordering = $this->getState()->get('list.ordering', 'pulls.pull_id');
|
||||||
if (!empty($applied))
|
$direction = $this->getState()->get('list.direction', 'DESC');
|
||||||
{
|
if (!empty($ordering)) {
|
||||||
// Not applied patches have a NULL value, so build our value part of the query based on this
|
$query->order($db->escape($ordering) . ' ' . $db->escape($direction));
|
||||||
$value = $applied === 'no' ? '0' : '1';
|
}
|
||||||
|
|
||||||
$query->where($db->quoteName('pulls.is_rtc') . ' = ' . $value);
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
$npm = $this->getState()->get('filter.npm');
|
/**
|
||||||
|
* Retrieves the array of authorized sort fields
|
||||||
if (!empty($npm))
|
*
|
||||||
{
|
* @return array
|
||||||
// Not applied patches have a NULL value, so build our value part of the query based on this
|
*
|
||||||
$value = $npm === 'no' ? '0' : '1';
|
* @since 2.0
|
||||||
|
*/
|
||||||
$query->where($db->quoteName('pulls.is_npm') . ' = ' . $value);
|
public function getSortFields()
|
||||||
}
|
{
|
||||||
|
return $this->sortFields;
|
||||||
$draft = $this->getState()->get('filter.draft');
|
}
|
||||||
|
|
||||||
if (!empty($draft))
|
/**
|
||||||
{
|
* Method to request new data from GitHub
|
||||||
// Not applied patches have a NULL value, so build our value part of the query based on this
|
*
|
||||||
$value = $draft === 'no' ? '0' : '1';
|
* @param integer $page The page of the request
|
||||||
|
*
|
||||||
$query->where($db->quoteName('pulls.is_draft') . ' = ' . $value);
|
* @return array
|
||||||
}
|
*
|
||||||
|
* @since 2.0
|
||||||
$labels = $this->getState()->get('filter.label');
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
if (!empty($labels) && $labels[0] !== '')
|
public function requestFromGithub($page)
|
||||||
{
|
{
|
||||||
$labelQuery
|
if ($page === 1) {
|
||||||
->select($db->quoteName('pulls_labels.pull_id'))
|
$this->getDbo()->truncateTable('#__patchtester_pulls');
|
||||||
->select(
|
$this->getDbo()->truncateTable('#__patchtester_pulls_labels');
|
||||||
'COUNT(' . $db->quoteName('pulls_labels.name') . ') AS '
|
}
|
||||||
. $db->quoteName('labelCount')
|
|
||||||
)
|
try {
|
||||||
->from(
|
// TODO - Option to configure the batch size
|
||||||
$db->quoteName(
|
$batchSize = 100;
|
||||||
'#__patchtester_pulls_labels', 'pulls_labels'
|
$pullsResponse = Helper::initializeGithub()->getOpenPulls($this->getState()->get('github_user'), $this->getState()->get('github_repo'), $page, $batchSize);
|
||||||
)
|
$pulls = json_decode($pullsResponse->body);
|
||||||
)
|
} catch (UnexpectedResponse $exception) {
|
||||||
->where(
|
throw new \RuntimeException(Text::sprintf('COM_PATCHTESTER_ERROR_GITHUB_FETCH', $exception->getMessage()), $exception->getCode(), $exception);
|
||||||
$db->quoteName('pulls_labels.name') . ' IN (' . implode(
|
}
|
||||||
',', $db->quote($labels)
|
|
||||||
) . ')'
|
// If this is page 1, let's check to see if we need to paginate
|
||||||
)
|
if ($page === 1) {
|
||||||
->group($db->quoteName('pulls_labels.pull_id'));
|
// Default this to being a single page of results
|
||||||
|
$lastPage = 1;
|
||||||
$query->leftJoin(
|
if (isset($pullsResponse->headers['link'])) {
|
||||||
'(' . $labelQuery->__toString() . ') AS ' . $db->quoteName(
|
$linkHeader = $pullsResponse->headers['link'];
|
||||||
'pulls_labels'
|
// The `joomla/http` 2.0 package uses PSR-7 Responses which has a different format for headers, check for this
|
||||||
)
|
if (is_array($linkHeader)) {
|
||||||
. ' ON ' . $db->quoteName('pulls_labels.pull_id') . ' = '
|
$linkHeader = $linkHeader[0];
|
||||||
. $db->quoteName('pulls.pull_id')
|
}
|
||||||
)
|
|
||||||
->where(
|
preg_match(
|
||||||
$db->quoteName('pulls_labels.labelCount') . ' = ' . count(
|
'/(\?page=[0-9]{1,3}&per_page=' . $batchSize
|
||||||
$labels
|
. '+>; rel=\"last\")/',
|
||||||
)
|
$linkHeader,
|
||||||
);
|
$matches
|
||||||
}
|
);
|
||||||
|
|
||||||
$ordering = $this->getState()->get('list.ordering', 'pulls.pull_id');
|
if ($matches && isset($matches[0])) {
|
||||||
$direction = $this->getState()->get('list.direction', 'DESC');
|
$pageSegment = str_replace(
|
||||||
|
'&per_page=' . $batchSize,
|
||||||
if (!empty($ordering))
|
'',
|
||||||
{
|
$matches[0]
|
||||||
$query->order(
|
);
|
||||||
$db->escape($ordering) . ' ' . $db->escape($direction)
|
preg_match('/\d+/', $pageSegment, $pages);
|
||||||
);
|
$lastPage = (int) $pages[0];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return $query;
|
}
|
||||||
}
|
|
||||||
|
// If there are no pulls to insert then bail, assume we're finished
|
||||||
/**
|
if (count($pulls) === 0) {
|
||||||
* Retrieves the array of authorized sort fields
|
return ['complete' => true];
|
||||||
*
|
}
|
||||||
* @return array
|
|
||||||
*
|
$data = [];
|
||||||
* @since 2.0
|
$labels = [];
|
||||||
*/
|
foreach ($pulls as $pull) {
|
||||||
public function getSortFields()
|
// Check if this PR is RTC and has a `PR-` branch label
|
||||||
{
|
$isRTC = false;
|
||||||
return $this->sortFields;
|
$isNPM = false;
|
||||||
}
|
$branch = $pull->base->ref;
|
||||||
|
foreach ($pull->labels as $label) {
|
||||||
/**
|
if (strtolower($label->name) === 'rtc') {
|
||||||
* Method to request new data from GitHub
|
$isRTC = true;
|
||||||
*
|
} elseif (
|
||||||
* @param integer $page The page of the request
|
in_array(strtolower($label->name), ['npm resource changed', 'composer dependency changed'], true)
|
||||||
*
|
) {
|
||||||
* @return array
|
$isNPM = true;
|
||||||
*
|
}
|
||||||
* @since 2.0
|
|
||||||
* @throws \RuntimeException
|
$labels[] = implode(',', [
|
||||||
*/
|
(int) $pull->number,
|
||||||
public function requestFromGithub($page)
|
$this->getDbo()->quote($label->name),
|
||||||
{
|
$this->getDbo()->quote($label->color),
|
||||||
if ($page === 1)
|
]);
|
||||||
{
|
}
|
||||||
$this->getDbo()->truncateTable('#__patchtester_pulls');
|
|
||||||
$this->getDbo()->truncateTable('#__patchtester_pulls_labels');
|
// Build the data object to store in the database
|
||||||
}
|
$pullData = [
|
||||||
|
(int) $pull->number,
|
||||||
try
|
$this->getDbo()->quote(HTMLHelper::_('string.truncate', $pull->title, 150)),
|
||||||
{
|
$this->getDbo()->quote(HTMLHelper::_('string.truncate', $pull->body, 100)),
|
||||||
// TODO - Option to configure the batch size
|
$this->getDbo()->quote($pull->html_url),
|
||||||
$batchSize = 100;
|
(int) $isRTC,
|
||||||
|
(int) $isNPM,
|
||||||
$pullsResponse = Helper::initializeGithub()->getOpenPulls(
|
$this->getDbo()->quote($branch),
|
||||||
$this->getState()->get('github_user'),
|
($pull->draft ? 1 : 0)
|
||||||
$this->getState()->get('github_repo'),
|
];
|
||||||
$page,
|
$data[] = implode(',', $pullData);
|
||||||
$batchSize
|
}
|
||||||
);
|
|
||||||
|
// If there are no pulls to insert then bail, assume we're finished
|
||||||
$pulls = json_decode($pullsResponse->body);
|
if (count($data) === 0) {
|
||||||
}
|
return array('complete' => true);
|
||||||
catch (UnexpectedResponse $exception)
|
}
|
||||||
{
|
|
||||||
throw new \RuntimeException(
|
try {
|
||||||
Text::sprintf(
|
$this->getDbo()->setQuery($this->getDbo()->getQuery(true)
|
||||||
'COM_PATCHTESTER_ERROR_GITHUB_FETCH',
|
->insert('#__patchtester_pulls')
|
||||||
$exception->getMessage()
|
->columns(['pull_id', 'title', 'description', 'pull_url',
|
||||||
),
|
'is_rtc', 'is_npm', 'branch', 'is_draft'])
|
||||||
$exception->getCode(),
|
->values($data));
|
||||||
$exception
|
$this->getDbo()->execute();
|
||||||
);
|
} catch (\RuntimeException $exception) {
|
||||||
}
|
throw new \RuntimeException(Text::sprintf('COM_PATCHTESTER_ERROR_INSERT_DATABASE', $exception->getMessage()), $exception->getCode(), $exception);
|
||||||
|
}
|
||||||
// If this is page 1, let's check to see if we need to paginate
|
|
||||||
if ($page === 1)
|
if ($labels) {
|
||||||
{
|
try {
|
||||||
// Default this to being a single page of results
|
$this->getDbo()->setQuery($this->getDbo()->getQuery(true)
|
||||||
$lastPage = 1;
|
->insert('#__patchtester_pulls_labels')
|
||||||
|
->columns(['pull_id', 'name', 'color'])
|
||||||
if (isset($pullsResponse->headers['link']))
|
->values($labels));
|
||||||
{
|
$this->getDbo()->execute();
|
||||||
$linkHeader = $pullsResponse->headers['link'];
|
} catch (\RuntimeException $exception) {
|
||||||
|
throw new \RuntimeException(
|
||||||
// The `joomla/http` 2.0 package uses PSR-7 Responses which has a different format for headers, check for this
|
Text::sprintf(
|
||||||
if (is_array($linkHeader))
|
'COM_PATCHTESTER_ERROR_INSERT_DATABASE',
|
||||||
{
|
$exception->getMessage()
|
||||||
$linkHeader = $linkHeader[0];
|
),
|
||||||
}
|
$exception->getCode(),
|
||||||
|
$exception
|
||||||
preg_match(
|
);
|
||||||
'/(\?page=[0-9]{1,3}&per_page=' . $batchSize
|
}
|
||||||
. '+>; rel=\"last\")/', $linkHeader, $matches
|
}
|
||||||
);
|
|
||||||
|
return [
|
||||||
if ($matches && isset($matches[0]))
|
'complete' => false,
|
||||||
{
|
'page' => ($page + 1),
|
||||||
$pageSegment = str_replace(
|
'lastPage' => $lastPage ?? false,
|
||||||
'&per_page=' . $batchSize, '', $matches[0]
|
];
|
||||||
);
|
}
|
||||||
|
|
||||||
preg_match('/\d+/', $pageSegment, $pages);
|
/**
|
||||||
$lastPage = (int) $pages[0];
|
* Truncates the pulls table
|
||||||
}
|
*
|
||||||
}
|
* @return void
|
||||||
}
|
*
|
||||||
|
* @since 2.0
|
||||||
// If there are no pulls to insert then bail, assume we're finished
|
*/
|
||||||
if (count($pulls) === 0)
|
public function truncateTable()
|
||||||
{
|
{
|
||||||
return ['complete' => true];
|
$this->getDbo()->truncateTable('#__patchtester_pulls');
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = [];
|
|
||||||
$labels = [];
|
|
||||||
|
|
||||||
foreach ($pulls as $pull)
|
|
||||||
{
|
|
||||||
// Check if this PR is RTC and has a `PR-` branch label
|
|
||||||
$isRTC = false;
|
|
||||||
$isNPM = false;
|
|
||||||
$branch = $pull->base->ref;
|
|
||||||
|
|
||||||
foreach ($pull->labels as $label)
|
|
||||||
{
|
|
||||||
if (strtolower($label->name) === 'rtc')
|
|
||||||
{
|
|
||||||
$isRTC = true;
|
|
||||||
}
|
|
||||||
elseif (in_array(
|
|
||||||
strtolower($label->name),
|
|
||||||
['npm resource changed', 'composer dependency changed'],
|
|
||||||
true
|
|
||||||
))
|
|
||||||
{
|
|
||||||
$isNPM = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$labels[] = implode(
|
|
||||||
',',
|
|
||||||
[
|
|
||||||
(int) $pull->number,
|
|
||||||
$this->getDbo()->quote($label->name),
|
|
||||||
$this->getDbo()->quote($label->color),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the data object to store in the database
|
|
||||||
$pullData = [
|
|
||||||
(int) $pull->number,
|
|
||||||
$this->getDbo()->quote(
|
|
||||||
HTMLHelper::_('string.truncate', $pull->title, 150)
|
|
||||||
),
|
|
||||||
$this->getDbo()->quote(
|
|
||||||
HTMLHelper::_('string.truncate', $pull->body, 100)
|
|
||||||
),
|
|
||||||
$this->getDbo()->quote($pull->html_url),
|
|
||||||
(int) $isRTC,
|
|
||||||
(int) $isNPM,
|
|
||||||
$this->getDbo()->quote($branch),
|
|
||||||
($pull->draft ? 1 : 0)
|
|
||||||
];
|
|
||||||
|
|
||||||
$data[] = implode(',', $pullData);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are no pulls to insert then bail, assume we're finished
|
|
||||||
if (count($data) === 0)
|
|
||||||
{
|
|
||||||
return array('complete' => true);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$this->getDbo()->setQuery(
|
|
||||||
$this->getDbo()->getQuery(true)
|
|
||||||
->insert('#__patchtester_pulls')
|
|
||||||
->columns(
|
|
||||||
['pull_id', 'title', 'description', 'pull_url',
|
|
||||||
'is_rtc', 'is_npm', 'branch', 'is_draft']
|
|
||||||
)
|
|
||||||
->values($data)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->getDbo()->execute();
|
|
||||||
}
|
|
||||||
catch (\RuntimeException $exception)
|
|
||||||
{
|
|
||||||
throw new \RuntimeException(
|
|
||||||
Text::sprintf(
|
|
||||||
'COM_PATCHTESTER_ERROR_INSERT_DATABASE',
|
|
||||||
$exception->getMessage()
|
|
||||||
),
|
|
||||||
$exception->getCode(),
|
|
||||||
$exception
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($labels)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$this->getDbo()->setQuery(
|
|
||||||
$this->getDbo()->getQuery(true)
|
|
||||||
->insert('#__patchtester_pulls_labels')
|
|
||||||
->columns(['pull_id', 'name', 'color'])
|
|
||||||
->values($labels)
|
|
||||||
);
|
|
||||||
$this->getDbo()->execute();
|
|
||||||
}
|
|
||||||
catch (\RuntimeException $exception)
|
|
||||||
{
|
|
||||||
throw new \RuntimeException(
|
|
||||||
Text::sprintf(
|
|
||||||
'COM_PATCHTESTER_ERROR_INSERT_DATABASE',
|
|
||||||
$exception->getMessage()
|
|
||||||
),
|
|
||||||
$exception->getCode(),
|
|
||||||
$exception
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'complete' => false,
|
|
||||||
'page' => ($page + 1),
|
|
||||||
'lastPage' => $lastPage ?? false,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Truncates the pulls table
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
|
||||||
public function truncateTable()
|
|
||||||
{
|
|
||||||
$this->getDbo()->truncateTable('#__patchtester_pulls');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -8,6 +9,10 @@
|
|||||||
|
|
||||||
namespace PatchTester\Model;
|
namespace PatchTester\Model;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Methods supporting applied pull requests.
|
* Methods supporting applied pull requests.
|
||||||
*
|
*
|
||||||
@ -15,36 +20,32 @@ namespace PatchTester\Model;
|
|||||||
*/
|
*/
|
||||||
class TestsModel extends AbstractModel
|
class TestsModel extends AbstractModel
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Retrieves a list of applied patches
|
* Retrieves a list of applied patches
|
||||||
*
|
*
|
||||||
* @return array List of applied patches
|
* @return array List of applied patches
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public function getAppliedPatches(): array
|
public function getAppliedPatches(): array
|
||||||
{
|
{
|
||||||
$db = $this->getDb();
|
$db = $this->getDb();
|
||||||
|
$db->setQuery($db->getQuery(true)
|
||||||
|
->select('*')
|
||||||
|
->from($db->quoteName('#__patchtester_tests'))
|
||||||
|
->where($db->quoteName('applied') . ' = 1'));
|
||||||
|
return $db->loadObjectList('pull_id');
|
||||||
|
}
|
||||||
|
|
||||||
$db->setQuery(
|
/**
|
||||||
$db->getQuery(true)
|
* Truncates the tests table
|
||||||
->select('*')
|
*
|
||||||
->from($db->quoteName('#__patchtester_tests'))
|
* @return void
|
||||||
->where($db->quoteName('applied') . ' = 1')
|
*
|
||||||
);
|
* @since 2.0
|
||||||
|
*/
|
||||||
return $db->loadObjectList('pull_id');
|
public function truncateTable(): void
|
||||||
}
|
{
|
||||||
|
$this->getDb()->truncateTable('#__patchtester_tests');
|
||||||
/**
|
}
|
||||||
* Truncates the tests table
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
|
||||||
public function truncateTable(): void
|
|
||||||
{
|
|
||||||
$this->getDb()->truncateTable('#__patchtester_tests');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -15,55 +16,53 @@ namespace PatchTester;
|
|||||||
*/
|
*/
|
||||||
abstract class TrackerHelper
|
abstract class TrackerHelper
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Array containing the supported repositories integrated with the Joomla! Issue Tracker
|
* Array containing the supported repositories integrated with the Joomla! Issue Tracker
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
private static $projects = array(
|
private static $projects = array(
|
||||||
'joomla-cms' => array(
|
'joomla-cms' => array(
|
||||||
'githubUser' => 'joomla',
|
'githubUser' => 'joomla',
|
||||||
'githubrepo' => 'joomla-cms',
|
'githubrepo' => 'joomla-cms',
|
||||||
'projectAlias' => 'joomla-cms',
|
'projectAlias' => 'joomla-cms',
|
||||||
),
|
),
|
||||||
'patchtester' => array(
|
'patchtester' => array(
|
||||||
'githubUser' => 'joomla-extensions',
|
'githubUser' => 'joomla-extensions',
|
||||||
'githubrepo' => 'patchtester',
|
'githubrepo' => 'patchtester',
|
||||||
'projectAlias' => 'patchtester',
|
'projectAlias' => 'patchtester',
|
||||||
),
|
),
|
||||||
'weblinks' => array(
|
'weblinks' => array(
|
||||||
'githubUser' => 'joomla-extensions',
|
'githubUser' => 'joomla-extensions',
|
||||||
'githubrepo' => 'weblinks',
|
'githubrepo' => 'weblinks',
|
||||||
'projectAlias' => 'weblinks',
|
'projectAlias' => 'weblinks',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the issue tracker project alias for a GitHub repository
|
* Get the issue tracker project alias for a GitHub repository
|
||||||
*
|
*
|
||||||
* @param string $githubUser The owner of the GitHub repository (user or organization)
|
* @param string $githubUser The owner of the GitHub repository (user or organization)
|
||||||
* @param string $githubRepo The GitHub repository name
|
* @param string $githubRepo The GitHub repository name
|
||||||
*
|
*
|
||||||
* @return string|boolean The project alias if supported or boolean false
|
* @return string|boolean The project alias if supported or boolean false
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public static function getTrackerAlias($githubUser, $githubRepo)
|
public static function getTrackerAlias($githubUser, $githubRepo)
|
||||||
{
|
{
|
||||||
// If the repo isn't even listed, no point in going further
|
// If the repo isn't even listed, no point in going further
|
||||||
if (!array_key_exists($githubRepo, self::$projects))
|
if (!array_key_exists($githubRepo, self::$projects)) {
|
||||||
{
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Now the GitHub user must match the project (we don't support forks, sorry!)
|
// Now the GitHub user must match the project (we don't support forks, sorry!)
|
||||||
if (self::$projects[$githubRepo]['githubUser'] !== $githubUser)
|
if (self::$projects[$githubRepo]['githubUser'] !== $githubUser) {
|
||||||
{
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// This project is supported
|
// This project is supported
|
||||||
return self::$projects[$githubRepo]['projectAlias'];
|
return self::$projects[$githubRepo]['projectAlias'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -12,6 +13,10 @@ use Joomla\CMS\Filesystem\Path;
|
|||||||
use Joomla\CMS\Language\Text;
|
use Joomla\CMS\Language\Text;
|
||||||
use PatchTester\Model\AbstractModel;
|
use PatchTester\Model\AbstractModel;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base HTML view for the patch testing component
|
* Base HTML view for the patch testing component
|
||||||
*
|
*
|
||||||
@ -19,204 +24,184 @@ use PatchTester\Model\AbstractModel;
|
|||||||
*/
|
*/
|
||||||
abstract class AbstractHtmlView extends AbstractView
|
abstract class AbstractHtmlView extends AbstractView
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The view layout.
|
* The view layout.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
protected $layout = 'default';
|
protected $layout = 'default';
|
||||||
|
/**
|
||||||
|
* The paths queue.
|
||||||
|
*
|
||||||
|
* @var SplPriorityQueue
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
protected $paths;
|
||||||
|
/**
|
||||||
|
* Method to instantiate the view.
|
||||||
|
*
|
||||||
|
* @param AbstractModel $model The model object.
|
||||||
|
* @param SplPriorityQueue $paths The paths queue.
|
||||||
|
*
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
public function __construct($model, \SplPriorityQueue $paths = null)
|
||||||
|
{
|
||||||
|
parent::__construct($model);
|
||||||
|
// Setup dependencies.
|
||||||
|
$this->paths = $paths ?: new \SplPriorityQueue();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The paths queue.
|
* Method to escape output.
|
||||||
*
|
*
|
||||||
* @var SplPriorityQueue
|
* @param string $output The output to escape.
|
||||||
* @since 4.0.0
|
*
|
||||||
*/
|
* @return string The escaped output.
|
||||||
protected $paths;
|
*
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
public function escape($output)
|
||||||
|
{
|
||||||
|
// Escape the output.
|
||||||
|
return htmlspecialchars($output, ENT_COMPAT, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to instantiate the view.
|
* Method to get the view layout.
|
||||||
*
|
*
|
||||||
* @param AbstractModel $model The model object.
|
* @return string The layout name.
|
||||||
* @param SplPriorityQueue $paths The paths queue.
|
*
|
||||||
*
|
* @since 4.0.0
|
||||||
* @since 4.0.0
|
*/
|
||||||
*/
|
public function getLayout()
|
||||||
public function __construct($model, \SplPriorityQueue $paths = null)
|
{
|
||||||
{
|
return $this->layout;
|
||||||
parent::__construct($model);
|
}
|
||||||
|
|
||||||
// Setup dependencies.
|
/**
|
||||||
$this->paths = $paths ?: new \SplPriorityQueue;
|
* Method to get the layout path.
|
||||||
}
|
*
|
||||||
|
* @param string $layout The layout name.
|
||||||
|
*
|
||||||
|
* @return mixed The layout file name if found, false otherwise.
|
||||||
|
*
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
public function getPath($layout)
|
||||||
|
{
|
||||||
|
// Get the layout file name.
|
||||||
|
$file = Path::clean($layout . '.php');
|
||||||
|
// Find the layout file path.
|
||||||
|
$path = Path::find(clone $this->paths, $file);
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to escape output.
|
* Method to get the view paths.
|
||||||
*
|
*
|
||||||
* @param string $output The output to escape.
|
* @return SplPriorityQueue The paths queue.
|
||||||
*
|
*
|
||||||
* @return string The escaped output.
|
* @since 4.0.0
|
||||||
*
|
*/
|
||||||
* @since 4.0.0
|
public function getPaths()
|
||||||
*/
|
{
|
||||||
public function escape($output)
|
return $this->paths;
|
||||||
{
|
}
|
||||||
// Escape the output.
|
|
||||||
return htmlspecialchars($output, ENT_COMPAT, 'UTF-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to get the view layout.
|
* Load a template file -- first look in the templates folder for an override
|
||||||
*
|
*
|
||||||
* @return string The layout name.
|
* @param string $tpl The name of the template source file; automatically searches the template paths and compiles as needed.
|
||||||
*
|
*
|
||||||
* @since 4.0.0
|
* @return string The output of the the template script.
|
||||||
*/
|
*
|
||||||
public function getLayout()
|
* @since 4.0.0
|
||||||
{
|
* @throws \RuntimeException
|
||||||
return $this->layout;
|
*/
|
||||||
}
|
public function loadTemplate($tpl = null)
|
||||||
|
{
|
||||||
|
// Get the path to the file
|
||||||
|
$file = $this->getLayout();
|
||||||
|
if (isset($tpl)) {
|
||||||
|
$file .= '_' . $tpl;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
$path = $this->getPath($file);
|
||||||
* Method to get the layout path.
|
if (!$path) {
|
||||||
*
|
throw new \RuntimeException(Text::sprintf('JLIB_APPLICATION_ERROR_LAYOUTFILE_NOT_FOUND', $file), 500);
|
||||||
* @param string $layout The layout name.
|
}
|
||||||
*
|
|
||||||
* @return mixed The layout file name if found, false otherwise.
|
|
||||||
*
|
|
||||||
* @since 4.0.0
|
|
||||||
*/
|
|
||||||
public function getPath($layout)
|
|
||||||
{
|
|
||||||
// Get the layout file name.
|
|
||||||
$file = Path::clean($layout . '.php');
|
|
||||||
|
|
||||||
// Find the layout file path.
|
// Unset so as not to introduce into template scope
|
||||||
$path = Path::find(clone $this->paths, $file);
|
unset($tpl);
|
||||||
|
unset($file);
|
||||||
|
// Never allow a 'this' property
|
||||||
|
if (isset($this->this)) {
|
||||||
|
unset($this->this);
|
||||||
|
}
|
||||||
|
|
||||||
return $path;
|
// Start an output buffer.
|
||||||
}
|
ob_start();
|
||||||
|
// Load the template.
|
||||||
|
include $path;
|
||||||
|
// Get the layout contents.
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to get the view paths.
|
* Method to render the view.
|
||||||
*
|
*
|
||||||
* @return SplPriorityQueue The paths queue.
|
* @return string The rendered view.
|
||||||
*
|
*
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
* @throws RuntimeException
|
||||||
public function getPaths()
|
*/
|
||||||
{
|
public function render()
|
||||||
return $this->paths;
|
{
|
||||||
}
|
// Get the layout path.
|
||||||
|
$path = $this->getPath($this->getLayout());
|
||||||
|
// Check if the layout path was found.
|
||||||
|
if (!$path) {
|
||||||
|
throw new \RuntimeException('Layout Path Not Found');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
// Start an output buffer.
|
||||||
* Load a template file -- first look in the templates folder for an override
|
ob_start();
|
||||||
*
|
// Load the layout.
|
||||||
* @param string $tpl The name of the template source file; automatically searches the template paths and compiles as needed.
|
include $path;
|
||||||
*
|
// Get the layout contents.
|
||||||
* @return string The output of the the template script.
|
$output = ob_get_clean();
|
||||||
*
|
return $output;
|
||||||
* @since 4.0.0
|
}
|
||||||
* @throws \RuntimeException
|
|
||||||
*/
|
|
||||||
public function loadTemplate($tpl = null)
|
|
||||||
{
|
|
||||||
// Get the path to the file
|
|
||||||
$file = $this->getLayout();
|
|
||||||
|
|
||||||
if (isset($tpl))
|
/**
|
||||||
{
|
* Method to set the view layout.
|
||||||
$file .= '_' . $tpl;
|
*
|
||||||
}
|
* @param string $layout The layout name.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
public function setLayout($layout)
|
||||||
|
{
|
||||||
|
$this->layout = $layout;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
$path = $this->getPath($file);
|
/**
|
||||||
|
* Method to set the view paths.
|
||||||
if (!$path)
|
*
|
||||||
{
|
* @param \SplPriorityQueue $paths The paths queue.
|
||||||
throw new \RuntimeException(Text::sprintf('JLIB_APPLICATION_ERROR_LAYOUTFILE_NOT_FOUND', $file), 500);
|
*
|
||||||
}
|
* @return $this
|
||||||
|
*
|
||||||
// Unset so as not to introduce into template scope
|
* @since 4.0.0
|
||||||
unset($tpl);
|
*/
|
||||||
unset($file);
|
public function setPaths(\SplPriorityQueue $paths)
|
||||||
|
{
|
||||||
// Never allow a 'this' property
|
$this->paths = $paths;
|
||||||
if (isset($this->this))
|
return $this;
|
||||||
{
|
}
|
||||||
unset($this->this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start an output buffer.
|
|
||||||
ob_start();
|
|
||||||
|
|
||||||
// Load the template.
|
|
||||||
include $path;
|
|
||||||
|
|
||||||
// Get the layout contents.
|
|
||||||
return ob_get_clean();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to render the view.
|
|
||||||
*
|
|
||||||
* @return string The rendered view.
|
|
||||||
*
|
|
||||||
* @since 4.0.0
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
// Get the layout path.
|
|
||||||
$path = $this->getPath($this->getLayout());
|
|
||||||
|
|
||||||
// Check if the layout path was found.
|
|
||||||
if (!$path)
|
|
||||||
{
|
|
||||||
throw new \RuntimeException('Layout Path Not Found');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start an output buffer.
|
|
||||||
ob_start();
|
|
||||||
|
|
||||||
// Load the layout.
|
|
||||||
include $path;
|
|
||||||
|
|
||||||
// Get the layout contents.
|
|
||||||
$output = ob_get_clean();
|
|
||||||
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to set the view layout.
|
|
||||||
*
|
|
||||||
* @param string $layout The layout name.
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*
|
|
||||||
* @since 4.0.0
|
|
||||||
*/
|
|
||||||
public function setLayout($layout)
|
|
||||||
{
|
|
||||||
$this->layout = $layout;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to set the view paths.
|
|
||||||
*
|
|
||||||
* @param \SplPriorityQueue $paths The paths queue.
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*
|
|
||||||
* @since 4.0.0
|
|
||||||
*/
|
|
||||||
public function setPaths(\SplPriorityQueue $paths)
|
|
||||||
{
|
|
||||||
$this->paths = $paths;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -17,37 +18,36 @@ use PatchTester\Model\AbstractModel;
|
|||||||
*/
|
*/
|
||||||
abstract class AbstractView
|
abstract class AbstractView
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The model object.
|
* The model object.
|
||||||
*
|
*
|
||||||
* @var AbstractModel
|
* @var AbstractModel
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
protected $model;
|
protected $model;
|
||||||
|
/**
|
||||||
|
* Method to instantiate the view.
|
||||||
|
*
|
||||||
|
* @param AbstractModel $model The model object.
|
||||||
|
*
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
public function __construct($model)
|
||||||
|
{
|
||||||
|
$this->model = $model;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to instantiate the view.
|
* Method to escape output.
|
||||||
*
|
*
|
||||||
* @param AbstractModel $model The model object.
|
* @param string $output The output to escape.
|
||||||
*
|
*
|
||||||
* @since 4.0.0
|
* @return string The escaped output.
|
||||||
*/
|
*
|
||||||
public function __construct($model)
|
* @since 4.0.0
|
||||||
{
|
*/
|
||||||
$this->model = $model;
|
public function escape($output)
|
||||||
}
|
{
|
||||||
|
return $output;
|
||||||
/**
|
}
|
||||||
* Method to escape output.
|
|
||||||
*
|
|
||||||
* @param string $output The output to escape.
|
|
||||||
*
|
|
||||||
* @return string The escaped output.
|
|
||||||
*
|
|
||||||
* @since 4.0.0
|
|
||||||
*/
|
|
||||||
public function escape($output)
|
|
||||||
{
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -8,6 +9,10 @@
|
|||||||
|
|
||||||
namespace PatchTester\View;
|
namespace PatchTester\View;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default HTML view class.
|
* Default HTML view class.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -10,6 +11,10 @@ use Joomla\CMS\Factory;
|
|||||||
use Joomla\CMS\HTML\HTMLHelper;
|
use Joomla\CMS\HTML\HTMLHelper;
|
||||||
use Joomla\CMS\Language\Text;
|
use Joomla\CMS\Language\Text;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/** @var \PatchTester\View\DefaultHtmlView $this */
|
/** @var \PatchTester\View\DefaultHtmlView $this */
|
||||||
|
|
||||||
HTMLHelper::_('jquery.framework');
|
HTMLHelper::_('jquery.framework');
|
||||||
@ -20,10 +25,10 @@ Text::script('COM_PATCHTESTER_FETCH_AN_ERROR_HAS_OCCURRED');
|
|||||||
?>
|
?>
|
||||||
|
|
||||||
<div id="patchtester-container">
|
<div id="patchtester-container">
|
||||||
<h1 id="patchtester-progress-header"><?php echo Text::_('COM_PATCHTESTER_FETCH_INITIALIZING'); ?></h1>
|
<h1 id="patchtester-progress-header"><?php echo Text::_('COM_PATCHTESTER_FETCH_INITIALIZING'); ?></h1>
|
||||||
<p id="patchtester-progress-message"><?php echo Text::_('COM_PATCHTESTER_FETCH_INITIALIZING_DESCRIPTION'); ?></p>
|
<p id="patchtester-progress-message"><?php echo Text::_('COM_PATCHTESTER_FETCH_INITIALIZING_DESCRIPTION'); ?></p>
|
||||||
<div id="progress" class="progress">
|
<div id="progress" class="progress">
|
||||||
<div id="progress-bar" class="progress-bar progress-bar-striped progress-bar-animated bg-success" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" role="progressbar"></div>
|
<div id="progress-bar" class="progress-bar progress-bar-striped progress-bar-animated bg-success" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" role="progressbar"></div>
|
||||||
</div>
|
</div>
|
||||||
<input id="patchtester-token" type="hidden" name="<?php echo Factory::getSession()->getFormToken(); ?>" value="1" />
|
<input id="patchtester-token" type="hidden" name="<?php echo Factory::getSession()->getFormToken(); ?>" value="1" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -18,6 +19,10 @@ use Joomla\Registry\Registry;
|
|||||||
use PatchTester\TrackerHelper;
|
use PatchTester\TrackerHelper;
|
||||||
use PatchTester\View\DefaultHtmlView;
|
use PatchTester\View\DefaultHtmlView;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View class for a list of pull requests.
|
* View class for a list of pull requests.
|
||||||
*
|
*
|
||||||
@ -27,140 +32,109 @@ use PatchTester\View\DefaultHtmlView;
|
|||||||
*/
|
*/
|
||||||
class PullsHtmlView extends DefaultHtmlView
|
class PullsHtmlView extends DefaultHtmlView
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Array containing environment errors
|
* Array containing environment errors
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
protected $envErrors = [];
|
protected $envErrors = [];
|
||||||
|
/**
|
||||||
|
* Array of open pull requests
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
protected $items;
|
||||||
|
/**
|
||||||
|
* Pagination object
|
||||||
|
*
|
||||||
|
* @var Pagination
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
protected $pagination;
|
||||||
|
/**
|
||||||
|
* Form object for search filters
|
||||||
|
*
|
||||||
|
* @var Form
|
||||||
|
* @since 4.1.0
|
||||||
|
*/
|
||||||
|
public $filterForm;
|
||||||
|
/**
|
||||||
|
* The active search filters
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
* @since 4.1.0
|
||||||
|
*/
|
||||||
|
public $activeFilters;
|
||||||
|
/**
|
||||||
|
* The model state
|
||||||
|
*
|
||||||
|
* @var Registry
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
protected $state;
|
||||||
|
/**
|
||||||
|
* The issue tracker project alias
|
||||||
|
*
|
||||||
|
* @var string|boolean
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
protected $trackerAlias;
|
||||||
|
/**
|
||||||
|
* Method to render the view.
|
||||||
|
*
|
||||||
|
* @return string The rendered view.
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function render(): string
|
||||||
|
{
|
||||||
|
if (!extension_loaded('openssl')) {
|
||||||
|
$this->envErrors[] = Text::_('COM_PATCHTESTER_REQUIREMENT_OPENSSL');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
if (!in_array('https', stream_get_wrappers(), true)) {
|
||||||
* Array of open pull requests
|
$this->envErrors[] = Text::_('COM_PATCHTESTER_REQUIREMENT_HTTPS');
|
||||||
*
|
}
|
||||||
* @var array
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
|
||||||
protected $items;
|
|
||||||
|
|
||||||
/**
|
if (!count($this->envErrors)) {
|
||||||
* Pagination object
|
$this->state = $this->model->getState();
|
||||||
*
|
$this->items = $this->model->getItems();
|
||||||
* @var Pagination
|
$this->pagination = $this->model->getPagination();
|
||||||
* @since 2.0
|
$this->filterForm = $this->model->getFilterForm();
|
||||||
*/
|
$this->activeFilters = $this->model->getActiveFilters();
|
||||||
protected $pagination;
|
$this->trackerAlias = TrackerHelper::getTrackerAlias($this->state->get('github_user'), $this->state->get('github_repo'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
// Change the layout if there are environment errors
|
||||||
* Form object for search filters
|
if (count($this->envErrors)) {
|
||||||
*
|
$this->setLayout('errors');
|
||||||
* @var Form
|
}
|
||||||
* @since 4.1.0
|
|
||||||
*/
|
|
||||||
public $filterForm;
|
|
||||||
|
|
||||||
/**
|
$this->addToolbar();
|
||||||
* The active search filters
|
Text::script('COM_PATCHTESTER_CONFIRM_RESET');
|
||||||
*
|
return parent::render();
|
||||||
* @var array
|
}
|
||||||
* @since 4.1.0
|
|
||||||
*/
|
|
||||||
public $activeFilters;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The model state
|
* Add the page title and toolbar.
|
||||||
*
|
*
|
||||||
* @var Registry
|
* @return void
|
||||||
* @since 2.0.0
|
*
|
||||||
*/
|
* @since 2.0.0
|
||||||
protected $state;
|
*/
|
||||||
|
protected function addToolbar(): void
|
||||||
|
{
|
||||||
|
ToolbarHelper::title(Text::_('COM_PATCHTESTER'), 'patchtester fas fa-save');
|
||||||
|
if (!count($this->envErrors)) {
|
||||||
|
$toolbar = Toolbar::getInstance('toolbar');
|
||||||
|
$toolbar->appendButton('Popup', 'sync', 'COM_PATCHTESTER_TOOLBAR_FETCH_DATA', 'index.php?option=com_patchtester&view=fetch&tmpl=component', 500, 210, 0, 0, 'window.parent.location.reload()', Text::_('COM_PATCHTESTER_HEADING_FETCH_DATA'));
|
||||||
|
// Add a reset button.
|
||||||
|
$toolbar->appendButton('Standard', 'expired', 'COM_PATCHTESTER_TOOLBAR_RESET', 'reset', false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
ToolbarHelper::preferences('com_patchtester');
|
||||||
* The issue tracker project alias
|
}
|
||||||
*
|
|
||||||
* @var string|boolean
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
|
||||||
protected $trackerAlias;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to render the view.
|
|
||||||
*
|
|
||||||
* @return string The rendered view.
|
|
||||||
*
|
|
||||||
* @since 2.0.0
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public function render(): string
|
|
||||||
{
|
|
||||||
if (!extension_loaded('openssl'))
|
|
||||||
{
|
|
||||||
$this->envErrors[] = Text::_('COM_PATCHTESTER_REQUIREMENT_OPENSSL');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!in_array('https', stream_get_wrappers(), true))
|
|
||||||
{
|
|
||||||
$this->envErrors[] = Text::_('COM_PATCHTESTER_REQUIREMENT_HTTPS');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!count($this->envErrors))
|
|
||||||
{
|
|
||||||
$this->state = $this->model->getState();
|
|
||||||
$this->items = $this->model->getItems();
|
|
||||||
$this->pagination = $this->model->getPagination();
|
|
||||||
$this->filterForm = $this->model->getFilterForm();
|
|
||||||
$this->activeFilters = $this->model->getActiveFilters();
|
|
||||||
$this->trackerAlias = TrackerHelper::getTrackerAlias(
|
|
||||||
$this->state->get('github_user'),
|
|
||||||
$this->state->get('github_repo')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change the layout if there are environment errors
|
|
||||||
if (count($this->envErrors))
|
|
||||||
{
|
|
||||||
$this->setLayout('errors');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->addToolbar();
|
|
||||||
|
|
||||||
Text::script('COM_PATCHTESTER_CONFIRM_RESET');
|
|
||||||
|
|
||||||
return parent::render();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the page title and toolbar.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
protected function addToolbar(): void
|
|
||||||
{
|
|
||||||
ToolbarHelper::title(Text::_('COM_PATCHTESTER'), 'patchtester fas fa-save');
|
|
||||||
|
|
||||||
if (!count($this->envErrors))
|
|
||||||
{
|
|
||||||
$toolbar = Toolbar::getInstance('toolbar');
|
|
||||||
|
|
||||||
$toolbar->appendButton(
|
|
||||||
'Popup',
|
|
||||||
'sync',
|
|
||||||
'COM_PATCHTESTER_TOOLBAR_FETCH_DATA',
|
|
||||||
'index.php?option=com_patchtester&view=fetch&tmpl=component',
|
|
||||||
500,
|
|
||||||
210,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'window.parent.location.reload()',
|
|
||||||
Text::_('COM_PATCHTESTER_HEADING_FETCH_DATA')
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add a reset button.
|
|
||||||
$toolbar->appendButton('Standard', 'expired', 'COM_PATCHTESTER_TOOLBAR_RESET', 'reset', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ToolbarHelper::preferences('com_patchtester');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -11,63 +12,71 @@ use Joomla\CMS\Language\Text;
|
|||||||
use Joomla\CMS\Layout\LayoutHelper;
|
use Joomla\CMS\Layout\LayoutHelper;
|
||||||
use Joomla\CMS\Router\Route;
|
use Joomla\CMS\Router\Route;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/** @var \PatchTester\View\Pulls\PullsHtmlView $this */
|
/** @var \PatchTester\View\Pulls\PullsHtmlView $this */
|
||||||
|
|
||||||
HTMLHelper::_('stylesheet', 'com_patchtester/octicons.css', ['version' => '3.5.0', 'relative' => true]);
|
HTMLHelper::_('stylesheet', 'com_patchtester/octicons.css', ['version' => '3.5.0', 'relative' => true]);
|
||||||
HTMLHelper::_('script', 'com_patchtester/patchtester.js', ['version' => 'auto', 'relative' => true]);
|
HTMLHelper::_('script', 'com_patchtester/patchtester.js', ['version' => 'auto', 'relative' => true]);
|
||||||
?>
|
?>
|
||||||
<form action="<?php echo Route::_('index.php?option=com_patchtester&view=pulls'); ?>" method="post" name="adminForm" id="adminForm">
|
<form action="<?php echo Route::_('index.php?option=com_patchtester&view=pulls'); ?>" method="post" name="adminForm" id="adminForm">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div id="j-main-container" class="j-main-container">
|
<div id="j-main-container" class="j-main-container">
|
||||||
<?php echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this]); ?>
|
<?php echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this]); ?>
|
||||||
<div id="j-main-container" class="j-main-container">
|
<div id="j-main-container" class="j-main-container">
|
||||||
<?php if (empty($this->items)) : ?>
|
<?php if (empty($this->items)) :
|
||||||
<div class="alert alert-info">
|
?>
|
||||||
<span class="fa fa-info-circle" aria-hidden="true"></span><span class="sr-only"><?php echo Text::_('INFO'); ?></span>
|
<div class="alert alert-info">
|
||||||
<?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?>
|
<span class="fa fa-info-circle" aria-hidden="true"></span><span class="sr-only"><?php echo Text::_('INFO'); ?></span>
|
||||||
</div>
|
<?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?>
|
||||||
<?php else : ?>
|
</div>
|
||||||
<table class="table">
|
<?php
|
||||||
<caption id="captionTable" class="sr-only">
|
else :
|
||||||
<?php echo Text::_('COM_PATCHTESTER_PULLS_TABLE_CAPTION'); ?>, <?php echo Text::_('JGLOBAL_SORTED_BY'); ?>
|
?>
|
||||||
</caption>
|
<table class="table">
|
||||||
<thead>
|
<caption id="captionTable" class="sr-only">
|
||||||
<tr>
|
<?php echo Text::_('COM_PATCHTESTER_PULLS_TABLE_CAPTION'); ?>, <?php echo Text::_('JGLOBAL_SORTED_BY'); ?>
|
||||||
<th scope="col" style="width:5%" class="text-center">
|
</caption>
|
||||||
<?php echo Text::_('COM_PATCHTESTER_PULL_ID'); ?>
|
<thead>
|
||||||
</th>
|
<tr>
|
||||||
<th scope="col" style="min-width:100px">
|
<th scope="col" style="width:5%" class="text-center">
|
||||||
<?php echo Text::_('JGLOBAL_TITLE'); ?>
|
<?php echo Text::_('COM_PATCHTESTER_PULL_ID'); ?>
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" style="width:8%" class="d-none d-md-table-cell text-center">
|
<th scope="col" style="min-width:100px">
|
||||||
<?php echo Text::_('COM_PATCHTESTER_BRANCH'); ?>
|
<?php echo Text::_('JGLOBAL_TITLE'); ?>
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" style="width:8%" class="d-none d-md-table-cell text-center">
|
<th scope="col" style="width:8%" class="d-none d-md-table-cell text-center">
|
||||||
<?php echo Text::_('COM_PATCHTESTER_READY_TO_COMMIT'); ?>
|
<?php echo Text::_('COM_PATCHTESTER_BRANCH'); ?>
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" style="width:10%" class="text-center">
|
<th scope="col" style="width:8%" class="d-none d-md-table-cell text-center">
|
||||||
<?php echo Text::_('JSTATUS'); ?>
|
<?php echo Text::_('COM_PATCHTESTER_READY_TO_COMMIT'); ?>
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" style="width:15%" class="text-center">
|
<th scope="col" style="width:10%" class="text-center">
|
||||||
<?php echo Text::_('COM_PATCHTESTER_TEST_THIS_PATCH'); ?>
|
<?php echo Text::_('JSTATUS'); ?>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
<th scope="col" style="width:15%" class="text-center">
|
||||||
</thead>
|
<?php echo Text::_('COM_PATCHTESTER_TEST_THIS_PATCH'); ?>
|
||||||
<tbody>
|
</th>
|
||||||
<?php echo $this->loadTemplate('items'); ?>
|
</tr>
|
||||||
</tbody>
|
</thead>
|
||||||
</table>
|
<tbody>
|
||||||
<?php endif; ?>
|
<?php echo $this->loadTemplate('items'); ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<?php
|
||||||
|
endif; ?>
|
||||||
|
|
||||||
<?php echo $this->pagination->getListFooter(); ?>
|
<?php echo $this->pagination->getListFooter(); ?>
|
||||||
|
|
||||||
<input type="hidden" name="task" value="" />
|
<input type="hidden" name="task" value="" />
|
||||||
<input type="hidden" name="boxchecked" value="0" />
|
<input type="hidden" name="boxchecked" value="0" />
|
||||||
<input type="hidden" name="pull_id" id="pull_id" value="" />
|
<input type="hidden" name="pull_id" id="pull_id" value="" />
|
||||||
<?php echo HTMLHelper::_('form.token'); ?>
|
<?php echo HTMLHelper::_('form.token'); ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -9,114 +10,141 @@
|
|||||||
use Joomla\CMS\Language\Text;
|
use Joomla\CMS\Language\Text;
|
||||||
use PatchTester\View\Pulls\PullsHtmlView;
|
use PatchTester\View\Pulls\PullsHtmlView;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/** @var PullsHtmlView $this */
|
/** @var PullsHtmlView $this */
|
||||||
|
|
||||||
foreach ($this->items as $i => $item) :
|
foreach ($this->items as $i => $item) :
|
||||||
$status = '';
|
$status = '';
|
||||||
|
if ($item->applied) :
|
||||||
if ($item->applied) :
|
$status = ' class="table-active"';
|
||||||
$status = ' class="table-active"';
|
endif;
|
||||||
endif;
|
?>
|
||||||
?>
|
<tr<?php echo $status; ?>>
|
||||||
<tr<?php echo $status; ?>>
|
<th scope="row" class="text-center">
|
||||||
<th scope="row" class="text-center">
|
<?php echo $item->pull_id; ?>
|
||||||
<?php echo $item->pull_id; ?>
|
<?php if ($item->is_draft) :
|
||||||
<?php if ($item->is_draft) : ?>
|
?>
|
||||||
<span class="badge" style="color: #FFFFFF; background-color: #6e7681">
|
<span class="badge" style="color: #FFFFFF; background-color: #6e7681">
|
||||||
<?php echo Text::_('COM_PATCHTESTER_IS_DRAFT'); ?>
|
<?php echo Text::_('COM_PATCHTESTER_IS_DRAFT'); ?>
|
||||||
</span>
|
</span>
|
||||||
<?php endif; ?>
|
<?php
|
||||||
</th>
|
endif; ?>
|
||||||
<td>
|
</th>
|
||||||
<span><?php echo $this->escape($item->title); ?></span>
|
<td>
|
||||||
<div role="tooltip" id="tip<?php echo $i; ?>">
|
<span><?php echo $this->escape($item->title); ?></span>
|
||||||
<?php echo $this->escape($item->description); ?>
|
<div role="tooltip" id="tip<?php echo $i; ?>">
|
||||||
</div>
|
<?php echo $this->escape($item->description); ?>
|
||||||
<div class="row">
|
</div>
|
||||||
<div class="col-md-auto">
|
<div class="row">
|
||||||
<a class="badge bg-info" href="<?php echo $item->pull_url; ?>" target="_blank">
|
<div class="col-md-auto">
|
||||||
<?php echo Text::_('COM_PATCHTESTER_VIEW_ON_GITHUB'); ?>
|
<a class="badge bg-info" href="<?php echo $item->pull_url; ?>" target="_blank">
|
||||||
</a>
|
<?php echo Text::_('COM_PATCHTESTER_VIEW_ON_GITHUB'); ?>
|
||||||
</div>
|
</a>
|
||||||
<?php if ($this->trackerAlias) : ?>
|
</div>
|
||||||
<div class="col-md-auto">
|
<?php if ($this->trackerAlias) :
|
||||||
<a class="badge bg-info"
|
?>
|
||||||
href="https://issues.joomla.org/tracker/<?php echo $this->trackerAlias; ?>/<?php echo $item->pull_id; ?>"
|
<div class="col-md-auto">
|
||||||
target="_blank">
|
<a class="badge bg-info"
|
||||||
<?php echo Text::_('COM_PATCHTESTER_VIEW_ON_JOOMLA_ISSUE_TRACKER'); ?>
|
href="https://issues.joomla.org/tracker/<?php echo $this->trackerAlias; ?>/<?php echo $item->pull_id; ?>"
|
||||||
</a>
|
target="_blank">
|
||||||
</div>
|
<?php echo Text::_('COM_PATCHTESTER_VIEW_ON_JOOMLA_ISSUE_TRACKER'); ?>
|
||||||
<?php endif; ?>
|
</a>
|
||||||
<?php if ($item->applied) : ?>
|
</div>
|
||||||
<div class="col-md-auto">
|
<?php
|
||||||
<span class="badge bg-info"><?php echo Text::sprintf('COM_PATCHTESTER_APPLIED_COMMIT_SHA', substr($item->sha, 0, 10)); ?></span>
|
endif; ?>
|
||||||
</div>
|
<?php if ($item->applied) :
|
||||||
<?php endif; ?>
|
?>
|
||||||
</div>
|
<div class="col-md-auto">
|
||||||
<?php if (count($item->labels) > 0) : ?>
|
<span class="badge bg-info"><?php echo Text::sprintf('COM_PATCHTESTER_APPLIED_COMMIT_SHA', substr($item->sha, 0, 10)); ?></span>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php if (count($item->labels) > 0) :
|
||||||
|
?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-auto">
|
<div class="col-md-auto">
|
||||||
<?php foreach ($item->labels as $label): ?>
|
<?php foreach ($item->labels as $label) :
|
||||||
|
?>
|
||||||
<?php
|
<?php
|
||||||
switch (strtolower($label->name))
|
switch (strtolower($label->name)) {
|
||||||
{
|
case 'a11y':
|
||||||
case 'a11y':
|
case 'conflicting files':
|
||||||
case 'conflicting files':
|
case 'documentation required':
|
||||||
case 'documentation required':
|
case 'information required':
|
||||||
case 'information required':
|
case 'j3 issue':
|
||||||
case 'j3 issue':
|
case 'language change':
|
||||||
case 'language change':
|
case 'mysql 5.7':
|
||||||
case 'mysql 5.7':
|
case 'needs new owner':
|
||||||
case 'needs new owner':
|
case 'no code attached yet':
|
||||||
case 'no code attached yet':
|
case 'pbf':
|
||||||
case 'pbf':
|
case 'pr-3.9-dev':
|
||||||
case 'pr-3.9-dev':
|
case 'pr-3.10-dev':
|
||||||
case 'pr-3.10-dev':
|
case 'pr-4.1-dev':
|
||||||
case 'pr-4.1-dev':
|
case 'pr-i10n_4.0-dev':
|
||||||
case 'pr-i10n_4.0-dev':
|
case 'pr-staging':
|
||||||
case 'pr-staging':
|
case 'release blocker':
|
||||||
case 'release blocker':
|
case 'rfc':
|
||||||
case 'rfc':
|
case 'test instructions missing':
|
||||||
case 'test instructions missing':
|
case 'updates requested':
|
||||||
case 'updates requested':
|
$textColor = '000000';
|
||||||
$textColor = '000000';
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$textColor = 'FFFFFF';
|
$textColor = 'FFFFFF';
|
||||||
break;
|
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
<span class="badge" style="color: #<?php echo $textColor; ?>; background-color: #<?php echo $label->color; ?>"><?php echo $label->name; ?></span>
|
<span class="badge" style="color: #<?php echo $textColor; ?>; background-color: #<?php echo $label->color; ?>"><?php echo $label->name; ?></span>
|
||||||
<?php endforeach; ?>
|
<?php
|
||||||
|
endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php
|
||||||
</td>
|
endif; ?>
|
||||||
<td class="d-none d-md-table-cell text-center">
|
</td>
|
||||||
<?php echo $this->escape($item->branch); ?>
|
<td class="d-none d-md-table-cell text-center">
|
||||||
</td>
|
<?php echo $this->escape($item->branch); ?>
|
||||||
<td class="d-none d-md-table-cell text-center">
|
</td>
|
||||||
<?php if ($item->is_rtc) : ?>
|
<td class="d-none d-md-table-cell text-center">
|
||||||
<span class="badge bg-success"><?php echo Text::_('JYES'); ?></span>
|
<?php if ($item->is_rtc) :
|
||||||
<?php else : ?>
|
?>
|
||||||
<span class="badge bg-secondary"><?php echo Text::_('JNO'); ?></span>
|
<span class="badge bg-success"><?php echo Text::_('JYES'); ?></span>
|
||||||
<?php endif; ?>
|
<?php
|
||||||
</td>
|
else :
|
||||||
<td class="text-center">
|
?>
|
||||||
<?php if ($item->applied) : ?>
|
<span class="badge bg-secondary"><?php echo Text::_('JNO'); ?></span>
|
||||||
<span class="badge bg-success"><?php echo Text::_('COM_PATCHTESTER_APPLIED'); ?></span>
|
<?php
|
||||||
<?php else : ?>
|
endif; ?>
|
||||||
<span class="badge bg-secondary"><?php echo Text::_('COM_PATCHTESTER_NOT_APPLIED'); ?></span>
|
</td>
|
||||||
<?php endif; ?>
|
<td class="text-center">
|
||||||
</td>
|
<?php if ($item->applied) :
|
||||||
<td class="text-center">
|
?>
|
||||||
<?php if ($item->applied) : ?>
|
<span class="badge bg-success"><?php echo Text::_('COM_PATCHTESTER_APPLIED'); ?></span>
|
||||||
<button type="button" class="btn btn-sm btn-success submitPatch"
|
<?php
|
||||||
data-task="revert" data-id="<?php echo (int) $item->applied; ?>"><?php echo Text::_('COM_PATCHTESTER_REVERT_PATCH'); ?></button>
|
else :
|
||||||
<?php else : ?>
|
?>
|
||||||
<button type="button" class="btn btn-sm btn-primary submitPatch"
|
<span class="badge bg-secondary"><?php echo Text::_('COM_PATCHTESTER_NOT_APPLIED'); ?></span>
|
||||||
data-task="apply" data-id="<?php echo (int) $item->pull_id; ?>"><?php echo Text::_('COM_PATCHTESTER_APPLY_PATCH'); ?></button>
|
<?php
|
||||||
<?php endif; ?>
|
endif; ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
<td class="text-center">
|
||||||
<?php endforeach;
|
<?php if ($item->applied) :
|
||||||
|
?>
|
||||||
|
<button type="button" class="btn btn-sm btn-success submitPatch"
|
||||||
|
data-task="revert" data-id="<?php echo (int) $item->applied; ?>"><?php echo Text::_('COM_PATCHTESTER_REVERT_PATCH'); ?></button>
|
||||||
|
<?php
|
||||||
|
else :
|
||||||
|
?>
|
||||||
|
<button type="button" class="btn btn-sm btn-primary submitPatch"
|
||||||
|
data-task="apply" data-id="<?php echo (int) $item->pull_id; ?>"><?php echo Text::_('COM_PATCHTESTER_APPLY_PATCH'); ?></button>
|
||||||
|
<?php
|
||||||
|
endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
endforeach;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -8,12 +9,18 @@
|
|||||||
|
|
||||||
use Joomla\CMS\Language\Text;
|
use Joomla\CMS\Language\Text;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/** @var \PatchTester\View\Pulls\PullsHtmlView $this */
|
/** @var \PatchTester\View\Pulls\PullsHtmlView $this */
|
||||||
?>
|
?>
|
||||||
<h3><?php echo Text::_('COM_PATCHTESTER_REQUIREMENTS_HEADING'); ?></h3>
|
<h3><?php echo Text::_('COM_PATCHTESTER_REQUIREMENTS_HEADING'); ?></h3>
|
||||||
<p><?php echo Text::_('COM_PATCHTESTER_REQUIREMENTS_NOT_MET'); ?></p>
|
<p><?php echo Text::_('COM_PATCHTESTER_REQUIREMENTS_NOT_MET'); ?></p>
|
||||||
<ul>
|
<ul>
|
||||||
<?php foreach ($this->envErrors as $error) : ?>
|
<?php foreach ($this->envErrors as $error) :
|
||||||
<li><?php echo $error; ?></li>
|
?>
|
||||||
<?php endforeach; ?>
|
<li><?php echo $error; ?></li>
|
||||||
|
<?php
|
||||||
|
endforeach; ?>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -6,36 +7,27 @@
|
|||||||
* @license GNU General Public License version 2 or later
|
* @license GNU General Public License version 2 or later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
\defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\CMS\Language\Text;
|
use Joomla\CMS\Language\Text;
|
||||||
|
if (!Factory::getUser()->authorise('core.manage', 'com_patchtester')) {
|
||||||
if (!Factory::getUser()->authorise('core.manage', 'com_patchtester'))
|
throw new RuntimeException(Text::_('JERROR_ALERTNOAUTHOR'), 403);
|
||||||
{
|
|
||||||
throw new RuntimeException(Text::_('JERROR_ALERTNOAUTHOR'), 403);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Application reference
|
// Application reference
|
||||||
$app = Factory::getApplication();
|
$app = Factory::getApplication();
|
||||||
|
|
||||||
// Import our Composer autoloader to load the component classes
|
// Import our Composer autoloader to load the component classes
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
// Build the controller class name based on task
|
// Build the controller class name based on task
|
||||||
$task = $app->input->getCmd('task', 'display');
|
$task = $app->input->getCmd('task', 'display');
|
||||||
|
|
||||||
// If $task is an empty string, apply our default since JInput might not
|
// If $task is an empty string, apply our default since JInput might not
|
||||||
if ($task === '')
|
if ($task === '') {
|
||||||
{
|
$task = 'display';
|
||||||
$task = 'display';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$class = '\\PatchTester\\Controller\\' . ucfirst(strtolower($task)) . 'Controller';
|
$class = '\\PatchTester\\Controller\\' . ucfirst(strtolower($task)) . 'Controller';
|
||||||
|
if (!class_exists($class)) {
|
||||||
if (!class_exists($class))
|
throw new InvalidArgumentException(Text::sprintf('JLIB_APPLICATION_ERROR_INVALID_CONTROLLER_CLASS', $class), 404);
|
||||||
{
|
|
||||||
throw new InvalidArgumentException(Text::sprintf('JLIB_APPLICATION_ERROR_INVALID_CONTROLLER_CLASS', $class), 404);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiate and execute the controller
|
// Instantiate and execute the controller
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch testing component for the Joomla! CMS
|
* Patch testing component for the Joomla! CMS
|
||||||
*
|
*
|
||||||
@ -12,6 +13,10 @@ use Joomla\CMS\Installer\Adapter\ComponentAdapter;
|
|||||||
use Joomla\CMS\Installer\InstallerScript;
|
use Joomla\CMS\Installer\InstallerScript;
|
||||||
use Joomla\CMS\Language\Text;
|
use Joomla\CMS\Language\Text;
|
||||||
|
|
||||||
|
// phpcs:disable PSR1.Files.SideEffects
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
// phpcs:enable PSR1.Files.SideEffects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installation class to perform additional changes during install/uninstall/update
|
* Installation class to perform additional changes during install/uninstall/update
|
||||||
*
|
*
|
||||||
@ -19,103 +24,99 @@ use Joomla\CMS\Language\Text;
|
|||||||
*/
|
*/
|
||||||
class Com_PatchtesterInstallerScript extends InstallerScript
|
class Com_PatchtesterInstallerScript extends InstallerScript
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Extension script constructor.
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->minimumJoomla = '4.0';
|
||||||
|
$this->minimumPhp = JOOMLA_MINIMUM_PHP;
|
||||||
|
$this->deleteFiles = array(
|
||||||
|
'/administrator/components/com_patchtester/PatchTester/View/Pulls/tmpl/default_errors.php',
|
||||||
|
);
|
||||||
|
$this->deleteFolders = array(
|
||||||
|
'/administrator/components/com_patchtester/PatchTester/Table',
|
||||||
|
'/components/com_patchtester',
|
||||||
|
);
|
||||||
|
Factory::getApplication()
|
||||||
|
->getLanguage()
|
||||||
|
->load('com_patchtester.sys', JPATH_ADMINISTRATOR, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extension script constructor.
|
* Show the message on install.
|
||||||
*
|
*
|
||||||
* @since 3.0.0
|
* @param ComponentAdapter $parent The class calling this method
|
||||||
*/
|
*
|
||||||
public function __construct()
|
* @return void
|
||||||
{
|
*
|
||||||
$this->minimumJoomla = '4.0';
|
* @since 4.0.0
|
||||||
$this->minimumPhp = JOOMLA_MINIMUM_PHP;
|
*/
|
||||||
|
public function install(ComponentAdapter $parent): void
|
||||||
|
{
|
||||||
|
?>
|
||||||
|
<h1>
|
||||||
|
<?php echo HTMLHelper::_('image', 'media/com_patchtester/images/icon-48-patchtester.png', Text::_('COM_PATCHTESTER')); ?>
|
||||||
|
<?php echo Text::_('COM_PATCHTESTER'); ?>
|
||||||
|
</h1>
|
||||||
|
<p><?php echo Text::_('COM_PATCHTESTER_INSTALL_INSTRUCTIONS'); ?></p>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
$this->deleteFiles = array(
|
/**
|
||||||
'/administrator/components/com_patchtester/PatchTester/View/Pulls/tmpl/default_errors.php',
|
* Show the message on install.
|
||||||
);
|
*
|
||||||
|
* @param ComponentAdapter $parent The class calling this method
|
||||||
$this->deleteFolders = array(
|
*
|
||||||
'/administrator/components/com_patchtester/PatchTester/Table',
|
* @return void
|
||||||
'/components/com_patchtester',
|
*
|
||||||
);
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
Factory::getApplication()
|
public function update(ComponentAdapter $parent): void
|
||||||
->getLanguage()
|
{
|
||||||
->load('com_patchtester.sys', JPATH_ADMINISTRATOR, null, true);
|
?>
|
||||||
}
|
<h1>
|
||||||
|
<?php echo HTMLHelper::_('image', 'media/com_patchtester/images/icon-48-patchtester.png', Text::_('COM_PATCHTESTER')); ?>
|
||||||
/**
|
<?php echo Text::_('COM_PATCHTESTER'); ?>
|
||||||
* Show the message on install.
|
</h1>
|
||||||
*
|
<p><?php echo Text::_('COM_PATCHTESTER_UPDATE_INSTRUCTIONS'); ?></p>
|
||||||
* @param ComponentAdapter $parent The class calling this method
|
<?php
|
||||||
*
|
}
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @since 4.0.0
|
|
||||||
*/
|
|
||||||
public function install(ComponentAdapter $parent): void
|
|
||||||
{
|
|
||||||
?>
|
|
||||||
<h1>
|
|
||||||
<?php echo HTMLHelper::_('image', 'media/com_patchtester/images/icon-48-patchtester.png', Text::_('COM_PATCHTESTER')); ?>
|
|
||||||
<?php echo Text::_('COM_PATCHTESTER'); ?>
|
|
||||||
</h1>
|
|
||||||
<p><?php echo Text::_('COM_PATCHTESTER_INSTALL_INSTRUCTIONS'); ?></p>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the message on install.
|
|
||||||
*
|
|
||||||
* @param ComponentAdapter $parent The class calling this method
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @since 4.0.0
|
|
||||||
*/
|
|
||||||
public function update(ComponentAdapter $parent): void
|
|
||||||
{
|
|
||||||
?>
|
|
||||||
<h1>
|
|
||||||
<?php echo HTMLHelper::_('image', 'media/com_patchtester/images/icon-48-patchtester.png', Text::_('COM_PATCHTESTER')); ?>
|
|
||||||
<?php echo Text::_('COM_PATCHTESTER'); ?>
|
|
||||||
</h1>
|
|
||||||
<p><?php echo Text::_('COM_PATCHTESTER_UPDATE_INSTRUCTIONS'); ?></p>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the message on install.
|
* Show the message on install.
|
||||||
*
|
*
|
||||||
* @param ComponentAdapter $parent The class calling this method
|
* @param ComponentAdapter $parent The class calling this method
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*
|
*
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
public function uninstall(ComponentAdapter $parent): void
|
public function uninstall(ComponentAdapter $parent): void
|
||||||
{
|
{
|
||||||
?>
|
?>
|
||||||
<h1>
|
<h1>
|
||||||
<?php echo HTMLHelper::_('image', 'media/com_patchtester/images/icon-48-patchtester.png', Text::_('COM_PATCHTESTER')); ?>
|
<?php echo HTMLHelper::_('image', 'media/com_patchtester/images/icon-48-patchtester.png', Text::_('COM_PATCHTESTER')); ?>
|
||||||
</h1>
|
</h1>
|
||||||
<p><?php echo Text::_('COM_PATCHTESTER_UNINSTALL_THANK_YOU'); ?></p>
|
<p><?php echo Text::_('COM_PATCHTESTER_UNINSTALL_THANK_YOU'); ?></p>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to perform changes during postflight
|
* Function to perform changes during postflight
|
||||||
*
|
*
|
||||||
* @param string $type The action being performed
|
* @param string $type The action being performed
|
||||||
* @param ComponentAdapter $parent The class calling this method
|
* @param ComponentAdapter $parent The class calling this method
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*
|
*
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
public function postflight(string $type, ComponentAdapter $parent): void
|
public function postflight(string $type, ComponentAdapter $parent): void
|
||||||
{
|
{
|
||||||
$this->removeFiles();
|
$this->removeFiles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env php
|
#!/usr/bin/env php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Script used to generate hashes for release packages
|
* Script used to generate hashes for release packages
|
||||||
*
|
*
|
||||||
@ -14,16 +15,14 @@ $packageDir = dirname(__DIR__) . '/packages';
|
|||||||
$hashes = array();
|
$hashes = array();
|
||||||
|
|
||||||
/** @var DirectoryIterator $file */
|
/** @var DirectoryIterator $file */
|
||||||
foreach (new DirectoryIterator($packageDir) as $file)
|
foreach (new DirectoryIterator($packageDir) as $file) {
|
||||||
{
|
if ($file->isDir() || $file->isDot()) {
|
||||||
if ($file->isDir() || $file->isDot())
|
continue;
|
||||||
{
|
}
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$hashes[$file->getFilename()] = array(
|
$hashes[$file->getFilename()] = array(
|
||||||
'sha384' => hash_file('sha384', $file->getPathname()),
|
'sha384' => hash_file('sha384', $file->getPathname()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$jsonOptions = PHP_VERSION_ID >= 50400 ? JSON_PRETTY_PRINT : 0;
|
$jsonOptions = PHP_VERSION_ID >= 50400 ? JSON_PRETTY_PRINT : 0;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env php
|
#!/usr/bin/env php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Script used to prepare a patchtester release
|
* Script used to prepare a patchtester release
|
||||||
*
|
*
|
||||||
@ -25,12 +26,12 @@ const PHP_TAB = "\t";
|
|||||||
// Functions.
|
// Functions.
|
||||||
function usage($command)
|
function usage($command)
|
||||||
{
|
{
|
||||||
echo PHP_EOL;
|
echo PHP_EOL;
|
||||||
echo 'Usage: php ' . $command . ' [options]' . PHP_EOL;
|
echo 'Usage: php ' . $command . ' [options]' . PHP_EOL;
|
||||||
echo PHP_TAB . '[options]:'.PHP_EOL;
|
echo PHP_TAB . '[options]:' . PHP_EOL;
|
||||||
echo PHP_TAB . PHP_TAB . '-v <version>:' . PHP_TAB . 'Version (ex: 3.0.0, 3.0.1-dev)' . PHP_EOL;
|
echo PHP_TAB . PHP_TAB . '-v <version>:' . PHP_TAB . 'Version (ex: 3.0.0, 3.0.1-dev)' . PHP_EOL;
|
||||||
echo PHP_TAB . PHP_TAB . '--exclude-manifest: Exclude updating the update server manifest';
|
echo PHP_TAB . PHP_TAB . '--exclude-manifest: Exclude updating the update server manifest';
|
||||||
echo PHP_EOL;
|
echo PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
$manifestFile = '/administrator/components/com_patchtester/patchtester.xml';
|
$manifestFile = '/administrator/components/com_patchtester/patchtester.xml';
|
||||||
@ -39,31 +40,27 @@ $updateServerFile = '/manifest.xml';
|
|||||||
// Check arguments (exit if incorrect cli arguments).
|
// Check arguments (exit if incorrect cli arguments).
|
||||||
$opts = getopt('v:', array('exclude-manifest'));
|
$opts = getopt('v:', array('exclude-manifest'));
|
||||||
|
|
||||||
if (empty($opts['v']))
|
if (empty($opts['v'])) {
|
||||||
{
|
usage($argv[0]);
|
||||||
usage($argv[0]);
|
die();
|
||||||
die();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check version string (exit if not correct).
|
// Check version string (exit if not correct).
|
||||||
$versionParts = explode('-', $opts['v']);
|
$versionParts = explode('-', $opts['v']);
|
||||||
|
|
||||||
if (!preg_match('#^[0-9]+\.[0-9]+\.[0-9]+$#', $versionParts[0]))
|
if (!preg_match('#^[0-9]+\.[0-9]+\.[0-9]+$#', $versionParts[0])) {
|
||||||
{
|
usage($argv[0]);
|
||||||
usage($argv[0]);
|
die();
|
||||||
die();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($versionParts[1]) && !preg_match('#(dev|alpha|beta|rc)[0-9]*#', $versionParts[1]))
|
if (isset($versionParts[1]) && !preg_match('#(dev|alpha|beta|rc)[0-9]*#', $versionParts[1])) {
|
||||||
{
|
usage($argv[0]);
|
||||||
usage($argv[0]);
|
die();
|
||||||
die();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($versionParts[2]) && $versionParts[2] !== 'dev')
|
if (isset($versionParts[2]) && $versionParts[2] !== 'dev') {
|
||||||
{
|
usage($argv[0]);
|
||||||
usage($argv[0]);
|
die();
|
||||||
die();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we use the correct language and timezone.
|
// Make sure we use the correct language and timezone.
|
||||||
@ -77,15 +74,15 @@ umask(022);
|
|||||||
$versionSubParts = explode('.', $versionParts[0]);
|
$versionSubParts = explode('.', $versionParts[0]);
|
||||||
|
|
||||||
$version = array(
|
$version = array(
|
||||||
'main' => $versionSubParts[0] . '.' . $versionSubParts[1],
|
'main' => $versionSubParts[0] . '.' . $versionSubParts[1],
|
||||||
'release' => $versionSubParts[0] . '.' . $versionSubParts[1] . '.' . $versionSubParts[2],
|
'release' => $versionSubParts[0] . '.' . $versionSubParts[1] . '.' . $versionSubParts[2],
|
||||||
'dev_devel' => $versionSubParts[2] . (!empty($versionParts[1]) ? '-' . $versionParts[1] : '') . (!empty($versionParts[2]) ? '-' . $versionParts[2] : ''),
|
'dev_devel' => $versionSubParts[2] . (!empty($versionParts[1]) ? '-' . $versionParts[1] : '') . (!empty($versionParts[2]) ? '-' . $versionParts[2] : ''),
|
||||||
'credate' => date('d-F-Y'),
|
'credate' => date('d-F-Y'),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Prints version information.
|
// Prints version information.
|
||||||
echo PHP_EOL;
|
echo PHP_EOL;
|
||||||
echo 'Version data:'. PHP_EOL;
|
echo 'Version data:' . PHP_EOL;
|
||||||
echo '- Main:' . PHP_TAB . PHP_TAB . PHP_TAB . $version['main'] . PHP_EOL;
|
echo '- Main:' . PHP_TAB . PHP_TAB . PHP_TAB . $version['main'] . PHP_EOL;
|
||||||
echo '- Release:' . PHP_TAB . PHP_TAB . $version['release'] . PHP_EOL;
|
echo '- Release:' . PHP_TAB . PHP_TAB . $version['release'] . PHP_EOL;
|
||||||
echo '- Full:' . PHP_TAB . PHP_TAB . PHP_TAB . $version['main'] . '.' . $version['dev_devel'] . PHP_EOL;
|
echo '- Full:' . PHP_TAB . PHP_TAB . PHP_TAB . $version['main'] . '.' . $version['dev_devel'] . PHP_EOL;
|
||||||
@ -96,33 +93,30 @@ echo PHP_EOL;
|
|||||||
$rootPath = dirname(dirname(__DIR__));
|
$rootPath = dirname(dirname(__DIR__));
|
||||||
|
|
||||||
// Updates the version and creation date in the component manifest file.
|
// Updates the version and creation date in the component manifest file.
|
||||||
if (file_exists($rootPath . $manifestFile))
|
if (file_exists($rootPath . $manifestFile)) {
|
||||||
{
|
$fileContents = file_get_contents($rootPath . $manifestFile);
|
||||||
$fileContents = file_get_contents($rootPath . $manifestFile);
|
$fileContents = preg_replace('#<version>[^<]*</version>#', '<version>' . $version['main'] . '.' . $version['dev_devel'] . '</version>', $fileContents);
|
||||||
$fileContents = preg_replace('#<version>[^<]*</version>#', '<version>' . $version['main'] . '.' . $version['dev_devel'] . '</version>', $fileContents);
|
$fileContents = preg_replace('#<creationDate>[^<]*</creationDate>#', '<creationDate>' . $version['credate'] . '</creationDate>', $fileContents);
|
||||||
$fileContents = preg_replace('#<creationDate>[^<]*</creationDate>#', '<creationDate>' . $version['credate'] . '</creationDate>', $fileContents);
|
file_put_contents($rootPath . $manifestFile, $fileContents);
|
||||||
file_put_contents($rootPath . $manifestFile, $fileContents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces the `__DEPLOY_VERSION__` marker with the "release" version number
|
// Replaces the `__DEPLOY_VERSION__` marker with the "release" version number
|
||||||
system('cd ' . $rootPath . ' && find administrator -name "*.php" -type f -exec sed -i "s/__DEPLOY_VERSION__/' . $version['release'] . '/g" "{}" \;');
|
system('cd ' . $rootPath . ' && find administrator -name "*.php" -type f -exec sed -i "s/__DEPLOY_VERSION__/' . $version['release'] . '/g" "{}" \;');
|
||||||
|
|
||||||
// If not instructed to exclude it, update the update server's manifest
|
// If not instructed to exclude it, update the update server's manifest
|
||||||
if (!isset($opts['exclude-manifest']))
|
if (!isset($opts['exclude-manifest'])) {
|
||||||
{
|
if (file_exists($rootPath . $updateServerFile)) {
|
||||||
if (file_exists($rootPath . $updateServerFile))
|
$fileContents = file_get_contents($rootPath . $updateServerFile);
|
||||||
{
|
$fileContents = preg_replace('#<infourl title="Patch Tester Component">[^<]*</infourl>#', '<infourl title="Patch Tester Component">https://github.com/joomla-extensions/patchtester/releases/tag/' . $version['release'] . '</infourl>', $fileContents);
|
||||||
$fileContents = file_get_contents($rootPath . $updateServerFile);
|
$fileContents = preg_replace('#<downloadurl type="full" format="zip">[^<]*</downloadurl>#', '<downloadurl type="full" format="zip">https://github.com/joomla-extensions/patchtester/releases/download/' . $version['release'] . '/com_patchtester_' . $version['release'] . '.zip</downloadurl>', $fileContents);
|
||||||
$fileContents = preg_replace('#<infourl title="Patch Tester Component">[^<]*</infourl>#', '<infourl title="Patch Tester Component">https://github.com/joomla-extensions/patchtester/releases/tag/' . $version['release'] . '</infourl>', $fileContents);
|
file_put_contents($rootPath . $updateServerFile, $fileContents);
|
||||||
$fileContents = preg_replace('#<downloadurl type="full" format="zip">[^<]*</downloadurl>#', '<downloadurl type="full" format="zip">https://github.com/joomla-extensions/patchtester/releases/download/' . $version['release'] . '/com_patchtester_' . $version['release'] . '.zip</downloadurl>', $fileContents);
|
|
||||||
file_put_contents($rootPath . $updateServerFile, $fileContents);
|
|
||||||
|
|
||||||
echo '*************' . PHP_EOL;
|
echo '*************' . PHP_EOL;
|
||||||
echo '* IMPORTANT *' . PHP_EOL;
|
echo '* IMPORTANT *' . PHP_EOL;
|
||||||
echo '*************' . PHP_EOL;
|
echo '*************' . PHP_EOL;
|
||||||
echo '' . PHP_EOL;
|
echo '' . PHP_EOL;
|
||||||
echo 'Ensure you regenerate the SHA384 package hash before publishing the updated manifest!!!' . PHP_EOL;
|
echo 'Ensure you regenerate the SHA384 package hash before publishing the updated manifest!!!' . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
echo 'Version bump complete!' . PHP_EOL . PHP_EOL;
|
echo 'Version bump complete!' . PHP_EOL . PHP_EOL;
|
||||||
|
@ -14,8 +14,6 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"joomla/crowdin-sync": "dev-master",
|
"joomla/crowdin-sync": "dev-master",
|
||||||
"joomla/cms-coding-standards": "~2.0.0-alpha2@dev",
|
|
||||||
"joomla/coding-standards": "~3.0@dev",
|
|
||||||
"squizlabs/php_codesniffer": "~3.0"
|
"squizlabs/php_codesniffer": "~3.0"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
980
composer.lock
generated
980
composer.lock
generated
File diff suppressed because it is too large
Load Diff
32
ruleset.xml
Normal file
32
ruleset.xml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<ruleset name="Joomla-CMS">
|
||||||
|
<description>The Joomla CMS PSR-12 exceptions.</description>
|
||||||
|
|
||||||
|
<!-- Exclude folders not containing production code -->
|
||||||
|
<exclude-pattern type="relative">build/packag*</exclude-pattern>
|
||||||
|
<exclude-pattern type="relative">administrator/components/com_patchtester/vendor/*</exclude-pattern>
|
||||||
|
|
||||||
|
<rule ref="PSR12">
|
||||||
|
<exclude name="Generic.Files.LineEndings"/>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- temporary extend the line length -->
|
||||||
|
<rule ref="Generic.Files.LineLength">
|
||||||
|
<properties>
|
||||||
|
<property name="lineLimit" value="560"/>
|
||||||
|
<property name="absoluteLineLimit" value="560"/>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule ref="PSR1.Files.SideEffects">
|
||||||
|
<exclude-pattern type="relative">build/patchtester/release\.php</exclude-pattern>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule ref="PSR1.Classes.ClassDeclaration">
|
||||||
|
<exclude-pattern type="relative">administrator/components/com_patchtester/script\.php</exclude-pattern>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule ref="Squiz.Classes.ValidClassName">
|
||||||
|
<exclude-pattern type="relative">administrator/components/com_patchtester/script\.php</exclude-pattern>
|
||||||
|
</rule>
|
||||||
|
</ruleset>
|
Loading…
Reference in New Issue
Block a user