drupalorg-1.0.x-dev/src/Plugin/QueueWorker/DrupalOrgIssueForksQueueWorker.php
src/Plugin/QueueWorker/DrupalOrgIssueForksQueueWorker.php
<?php
namespace Drupal\drupalorg\Plugin\QueueWorker;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Queue\QueueFactory;
use Drupal\Core\Queue\QueueWorkerBase;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\drupalorg\Traits\GitLabClientTrait;
use Drupal\drupalorg\UserService;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines 'drupalorg_issue_forks_queue_worker' queue worker.
*
* Run via `drush` like this:
* `drush queue:run drupalorg_issue_forks_queue_worker`.
*
* @QueueWorker(
* id = "drupalorg_issue_forks_queue_worker",
* title = @Translation("Issue Forks Queue Worker")
* )
*/
class DrupalOrgIssueForksQueueWorker extends QueueWorkerBase implements ContainerFactoryPluginInterface {
use GitLabClientTrait;
use StringTranslationTrait;
/**
* Number of attempts to retry post fork actions.
*
* @var int
*/
const POST_FORK_ACTIONS_ATTEMPTS = 20;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('drupalorg.user_service'),
$container->get('logger.factory')->get('drupalorg'),
$container->get('queue')
);
}
/**
* {@inheritdoc}
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
protected UserService $userService,
protected LoggerInterface $logger,
protected QueueFactory $queueFactory,
) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
}
/**
* {@inheritdoc}
*/
public function processItem($data) {
if (!$this->validateItem($data)) {
return FALSE;
}
switch ($data['action']) {
case 'post_fork_creation':
$this->postForkCreation($data);
break;
}
}
/**
* Validate item array to make sure all key elements are there.
*
* @param array $data
* Item to validate.
*
* @return bool
* Whether the item was valid or not.
*/
protected function validateItem(array $data) {
if (
empty($data['action']) ||
empty($data['fork_id']) ||
empty($data['issue_id']) ||
empty($data['user_id'])
) {
return FALSE;
}
return TRUE;
}
/**
* Creates a branch based on the issue id and adds the user as member.
*
* @param array $data
* Data given to the queue containing user, issue and fork information.
*/
protected function postForkCreation(array $data) {
$client = $this->getGitLabClient();
try {
$fork = $client->projects()->show($data['fork_id']);
// Was there any error in the fork creation?
if (!empty($fork['import_error'])) {
$this->logger->error('Import failed for @name: @import_error', [
'@name' => $data['fork_id'],
'@import_error' => $fork['import_error'],
]);
throw new \Exception($this->t('Import failed for @name', [
'@name' => $data['fork_id'],
]));
}
// Check status, make sure the fork is finished, otherwise requeue.
if ($fork['import_status'] !== 'finished') {
if (empty($data['attempts'])) {
$data['attempts'] = 0;
}
$data['attempts']++;
if ($data['attempts'] <= self::POST_FORK_ACTIONS_ATTEMPTS) {
// Try again in this queue.
$this->queueFactory->get('drupalorg_issue_forks_queue_worker')->createItem($data);
$this->logger->warning('Import did not finish for @name: re-queue item attempt @attempt/@max.', [
'@name' => $data['fork_id'],
'@attempt' => $data['attempts'],
'@max' => self::POST_FORK_ACTIONS_ATTEMPTS,
]);
}
else {
// Limit exceeded, send to the delayed queue to give it a breather.
$this->logger->error('Import did not finish for @name: max-attempts(@max) exceeded.', [
'@name' => $data['fork_id'],
'@max' => self::POST_FORK_ACTIONS_ATTEMPTS,
]);
$data['delayed_at'] = strtotime('now');
$data['queue'] = $this->getPluginId();
$this->queueFactory->get('drupalorg_delayed_items_queue_worker')->createItem($data);
}
return;
}
// Create a branch with the issue number in it.
if (!empty($data['source_branch']) && !empty($data['branch_name'])) {
$client->repositories()->createBranch($data['fork_id'], $data['branch_name'], $data['source_branch']);
}
// Update forked project description and settings.
$options = $this->getForkDefaultOptions();
$options['description'] = 'For collaboration on ' . $data['issue_link'];
$client->projects()->update($fork['id'], $options);
}
catch (\Throwable $e) {
$this->logger->error('Error in post fork creation. Message: @message', [
'@message' => $e->getMessage(),
]);
}
}
}
