You are here

class CircleV2 in Build Hooks 3.x

Same name and namespace in other branches
  1. 8.2 modules/build_hooks_circleci/src/Plugin/FrontendEnvironment/CircleV2.php \Drupal\build_hooks_circleci\Plugin\FrontendEnvironment\CircleV2

Defines a circle v2 environment.

Plugin annotation


@FrontendEnvironment(
 id = "circleciv2",
 label = "Circle CI (V2)",
 description = "An Circle CI environment using Version 2 of their API"
)

Hierarchy

Expanded class hierarchy of CircleV2

File

modules/build_hooks_circleci/src/Plugin/FrontendEnvironment/CircleV2.php, line 27

Namespace

Drupal\build_hooks_circleci\Plugin\FrontendEnvironment
View source
class CircleV2 extends FrontendEnvironmentBase implements ContainerFactoryPluginInterface {

  /**
   * HTTP client.
   *
   * @var \GuzzleHttp\ClientInterface
   */
  private $httpClient;

  /**
   * Date formatter.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  private $formatter;

  /**
   * Constructs a new CircleV2.
   *
   * @param array $configuration
   *   Configuration.
   * @param string $plugin_id
   *   Plugin ID.
   * @param mixed $plugin_definition
   *   Plugin definition.
   * @param \GuzzleHttp\ClientInterface $httpClient
   *   HTTP client.
   * @param \Drupal\Core\Datetime\DateFormatterInterface $formatter
   *   Date formatter.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, ClientInterface $httpClient, DateFormatterInterface $formatter) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->httpClient = $httpClient;
    $this->formatter = $formatter;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static($configuration, $plugin_id, $plugin_definition, $container
      ->get('http_client'), $container
      ->get('date.formatter'));
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return parent::defaultConfiguration() + [
      'token' => '',
      'type' => 'branch',
      'project' => '',
      'reference' => '',
      'parameters' => [],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function frontEndEnvironmentForm($form, FormStateInterface $form_state) {
    $build = parent::frontEndEnvironmentForm($form, $form_state);
    $build['token'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Token'),
      '#default_value' => $this->configuration['token'],
      '#required' => TRUE,
    ];
    $build['project'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Project'),
      '#default_value' => $this->configuration['project'],
      '#required' => TRUE,
      '#description' => $this
        ->t('Enter your project in the form organisation/repository'),
    ];
    $build['type'] = [
      '#type' => 'radios',
      '#title' => $this
        ->t('Reference type'),
      '#default_value' => $this->configuration['type'],
      '#options' => [
        'branch' => $this
          ->t('Branch'),
        'tag' => $this
          ->t('Tag'),
      ],
    ];
    $build['reference'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Branch / Tag'),
      '#default_value' => $this->configuration['reference'],
      '#required' => TRUE,
    ];
    $build['parameters'] = [
      '#caption' => $this
        ->t('Parameters'),
      '#prefix' => '<div id="parameters-add-more">',
      '#suffix' => '</div>',
      '#type' => 'table',
      '#header' => [
        $this
          ->t('Name'),
        $this
          ->t('Value'),
        $this
          ->t('Remove'),
      ],
    ];
    $parameters = $form_state
      ->getCompleteFormState()
      ->getValue([
      'settings',
      'parameters',
    ], $this->configuration['parameters'] ?: [
      [
        'name' => '',
        'type' => 'string',
        'value' => '',
      ],
    ]);
    foreach ($parameters as $ix => $parameter) {
      $build['parameters'][$ix] = [
        'name' => [
          '#type' => 'textfield',
          '#title_display' => 'invisible',
          '#title' => $this
            ->t('Name<span class="visually-hidden"> of parameter @ix</span>', [
            '@ix' => $ix + 1,
          ]),
          '#default_value' => $parameter['name'],
        ],
        'type' => [
          '#type' => 'select',
          '#title_display' => 'invisible',
          '#title' => $this
            ->t('Type<span class="visually-hidden"> of parameter @ix</span>', [
            '@ix' => $ix + 1,
          ]),
          '#options' => [
            'string' => $this
              ->t('String'),
            'boolean' => $this
              ->t('Boolean'),
            'integer' => $this
              ->t('Integer'),
          ],
          '#default_value' => $parameter['type'],
        ],
        'value' => [
          '#type' => 'textfield',
          '#title_display' => 'invisible',
          '#title' => $this
            ->t('Value<span class="visually-hidden"> of parameter @ix</span>', [
            '@ix' => $ix + 1,
          ]),
          '#default_value' => $parameter['value'],
        ],
        'remove' => [
          '#type' => 'submit',
          '#value' => $this
            ->t('Remove %label', [
            '%label' => $parameter['name'] ?: $this
              ->t('item @ix', [
              '@ix' => $ix + 1,
            ]),
          ]),
          '#submit' => [
            [
              static::class,
              'removeParameterSubmit',
            ],
          ],
          '#ajax' => [
            'callback' => [
              static::class,
              'updateForm',
            ],
            'wrapper' => 'parameters-add-more',
            'effect' => 'fade',
            'method' => 'replaceWith',
          ],
        ],
      ];
    }
    $build['add_another'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Add another parameter'),
      '#submit' => [
        [
          static::class,
          'addMoreSubmit',
        ],
      ],
      '#ajax' => [
        'callback' => [
          static::class,
          'updateForm',
        ],
        'wrapper' => 'parameters-add-more',
        'effect' => 'fade',
        'method' => 'replaceWith',
      ],
    ];
    $build['help'] = [
      '#markup' => $this
        ->t('<p>Parameters to send to CircleCI. To send a value of False for a boolean, enter 0.</p>'),
    ];
    return $build;
  }

  /**
   * Submission handler for the "Add another parameter" button.
   */
  public static function addMoreSubmit(array $form, FormStateInterface $form_state) {
    $parameters = $form_state
      ->getValue([
      'settings',
      'parameters',
    ], []);
    $parameters[] = [
      'name' => '',
      'type' => 'string',
      'value' => '',
    ];
    $form_state
      ->setValue([
      'settings',
      'parameters',
    ], $parameters);
    $form_state
      ->setRebuild();
  }

  /**
   * Submission handler for the "Remove parameter" button.
   */
  public static function removeParameterSubmit(array $form, FormStateInterface $form_state) {
    $button = $form_state
      ->getTriggeringElement();
    $parameters = $form_state
      ->getValue([
      'settings',
      'parameters',
    ], []);
    $parents = $button['#parents'];

    // Remove the button.
    array_pop($parents);
    unset($parameters[end($parents)]);
    $form_state
      ->setValue([
      'settings',
      'parameters',
    ], array_values($parameters));
    $form_state
      ->setRebuild();
  }

  /**
   * Ajax callback for the "Add another parameter" button.
   */
  public function updateForm(array $form, FormStateInterface $form_state) {
    return $form['settings']['parameters'] ?? [];
  }

  /**
   * {@inheritdoc}
   */
  public function frontEndEnvironmentSubmit($form, FormStateInterface $form_state) {
    parent::frontEndEnvironmentSubmit($form, $form_state);
    $this->configuration['token'] = $form_state
      ->getValue('token');
    $this->configuration['project'] = $form_state
      ->getValue('project');
    $this->configuration['reference'] = $form_state
      ->getValue('reference');
    $this->configuration['type'] = $form_state
      ->getValue('type');
    $this->configuration['parameters'] = array_filter($form_state
      ->getValue('parameters'), function (array $item) {
      return !empty($item['name']);
    });
  }

  /**
   * {@inheritdoc}
   */
  public function getBuildHookDetails() {
    $buildHookDetails = new BuildHookDetails();
    $buildHookDetails
      ->setOptions([
      'json' => [
        $this->configuration['type'] => $this->configuration['reference'],
        'parameters' => array_reduce($this->configuration['parameters'], function (array $carry, array $item) {
          switch ($item['type']) {
            case 'boolean':
              $carry[$item['name']] = (bool) $item['value'];
              return $carry;
            case 'integer':
              $carry[$item['name']] = (int) $item['value'];
              return $carry;
            default:
              $carry[$item['name']] = $item['value'];
          }
          return $carry;
        }, []),
      ],
      'auth' => [
        $this->configuration['token'],
        '',
      ],
    ]);
    $buildHookDetails
      ->setMethod('POST');
    $buildHookDetails
      ->setUrl('https://circleci.com/api/v2/project/gh/' . $this->configuration['project'] . '/pipeline');
    return $buildHookDetails;
  }

  /**
   * {@inheritdoc}
   */
  public function getAdditionalDeployFormElements(FormStateInterface $form_state) {
    try {
      $response = $this->httpClient
        ->request('GET', sprintf('https://circleci.com/api/v2/project/gh/%s/pipeline/mine?branch=%s', $this->configuration['project'], $this->configuration['reference']), [
        'auth' => [
          $this->configuration['token'],
          '',
        ],
      ]);
    } catch (GuzzleException $e) {
      return [
        'error' => [
          '#markup' => $this
            ->t('Could not get list of recent builds'),
        ],
      ];
    }
    $body = Json::decode($response
      ->getBody());
    $build['builds'] = [
      '#type' => 'table',
      '#attributes' => [
        'id' => 'ajax-replace-table',
      ],
      '#header' => [
        $this
          ->t('Created'),
        $this
          ->t('Updated'),
        $this
          ->t('Status'),
        $this
          ->t('Link'),
      ],
      '#empty' => $this
        ->t('No recent builds for reference %reference', [
        '%reference' => $this->configuration['reference'],
      ]),
      '#caption' => $this
        ->t('Last 5 builds'),
    ];
    foreach (array_slice(array_filter($body['items'], function (array $item) {
      return ($item['vcs']['branch'] ?? FALSE) === $this->configuration['reference'];
    }), 0, 5) as $item) {
      try {
        $workflow_response = $this->httpClient
          ->request('GET', 'https://circleci.com/api/v2/pipeline/' . $item['id'] . '/workflow', [
          'auth' => [
            $this->configuration['token'],
            '',
          ],
        ]);
        $workflows = Json::decode($workflow_response
          ->getBody());
      } catch (GuzzleException $e) {
        $build['builds']['#rows'][] = [
          $this->formatter
            ->format(\DateTime::createFromFormat(\DateTime::RFC3339_EXTENDED, $item['created_at'])
            ->getTimestamp(), 'medium'),
          $this->formatter
            ->format(\DateTime::createFromFormat(\DateTime::RFC3339_EXTENDED, $item['updated_at'])
            ->getTimestamp(), 'medium'),
          $this
            ->t('Could not get workflows'),
          '-',
        ];
        continue;
      }
      $worflow = reset($workflows['items']);
      $build['builds']['#rows'][] = [
        $this->formatter
          ->format(\DateTime::createFromFormat(\DateTime::RFC3339_EXTENDED, $item['created_at'])
          ->getTimestamp(), 'medium'),
        $this->formatter
          ->format(\DateTime::createFromFormat(\DateTime::RFC3339_EXTENDED, $item['updated_at'])
          ->getTimestamp(), 'medium'),
        Unicode::ucfirst($worflow['status']),
        [
          'data' => [
            '#type' => 'link',
            '#url' => Url::fromUri(sprintf('https://app.circleci.com/pipelines/github/%s/%d/workflows/%s', $this->configuration['project'], $item['number'], $worflow['id'])),
            '#title' => $this
              ->t('View'),
          ],
        ],
      ];
    }
    $build['refresher'] = [
      '#type' => 'button',
      '#ajax' => [
        'callback' => [
          self::class,
          'refresh',
        ],
        'wrapper' => 'ajax-replace-table',
        'effect' => 'fade',
        'progress' => [
          'type' => 'throbber',
          'message' => $this
            ->t('Refreshing status...'),
        ],
      ],
      '#value' => $this
        ->t('Refresh'),
    ];
    return $build;
  }

  /**
   * Ajax form callback to rebuild the latest deployments table.
   *
   * @param array $form
   *   The form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state of the form.
   *
   * @return array
   *   The form array to add back to the form.
   */
  public static function refresh(array $form, FormStateInterface $form_state) {
    return $form['builds'];
  }

  /**
   * {@inheritdoc}
   */
  public function deploymentWasTriggered(ResponseInterface $response) : bool {
    return $response
      ->getStatusCode() < 300 && $response
      ->getStatusCode() >= 200;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CircleV2::$formatter private property Date formatter.
CircleV2::$httpClient private property HTTP client.
CircleV2::addMoreSubmit public static function Submission handler for the "Add another parameter" button.
CircleV2::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create
CircleV2::defaultConfiguration public function Gets default configuration for this plugin. Overrides FrontendEnvironmentBase::defaultConfiguration
CircleV2::deploymentWasTriggered public function Determine if the deployment was triggered successfully. Overrides FrontendEnvironmentBase::deploymentWasTriggered
CircleV2::frontEndEnvironmentForm public function Overrides FrontendEnvironmentBase::frontEndEnvironmentForm
CircleV2::frontEndEnvironmentSubmit public function Overrides FrontendEnvironmentBase::frontEndEnvironmentSubmit
CircleV2::getAdditionalDeployFormElements public function Allows the plugin to add elements to the deployment form. Overrides FrontendEnvironmentInterface::getAdditionalDeployFormElements
CircleV2::getBuildHookDetails public function Get the info to trigger the hook based on the configuration of the plugin. Overrides FrontendEnvironmentInterface::getBuildHookDetails
CircleV2::refresh public static function Ajax form callback to rebuild the latest deployments table.
CircleV2::removeParameterSubmit public static function Submission handler for the "Remove parameter" button.
CircleV2::updateForm public function Ajax callback for the "Add another parameter" button.
CircleV2::__construct public function Constructs a new CircleV2. Overrides FrontendEnvironmentBase::__construct
FrontendEnvironmentBase::$transliteration protected property The transliteration service.
FrontendEnvironmentBase::baseConfigurationDefaults protected function Returns generic default configuration for frontend environment plugins.
FrontendEnvironmentBase::buildConfigurationForm public function Form constructor. Overrides PluginFormInterface::buildConfigurationForm
FrontendEnvironmentBase::calculateDependencies public function Calculates dependencies for the configured plugin. Overrides DependentPluginInterface::calculateDependencies
FrontendEnvironmentBase::frontEndEnvironmentFormValidate public function 1
FrontendEnvironmentBase::getConfiguration public function Gets this plugin's configuration. Overrides ConfigurableInterface::getConfiguration
FrontendEnvironmentBase::getMachineNameSuggestion public function
FrontendEnvironmentBase::label public function
FrontendEnvironmentBase::preDeploymentTrigger public function React before a build is triggered. Overrides FrontendEnvironmentInterface::preDeploymentTrigger 1
FrontendEnvironmentBase::setConfiguration public function Sets the configuration for this plugin instance. Overrides ConfigurableInterface::setConfiguration
FrontendEnvironmentBase::setConfigurationValue public function
FrontendEnvironmentBase::setTransliteration public function Sets the transliteration service.
FrontendEnvironmentBase::submitConfigurationForm public function Form submission handler. Overrides PluginFormInterface::submitConfigurationForm
FrontendEnvironmentBase::transliteration protected function Wraps the transliteration service.
FrontendEnvironmentBase::validateConfigurationForm public function Form validation handler. Overrides PluginFormInterface::validateConfigurationForm
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 2
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
PluginWithFormsTrait::getFormClass public function Implements \Drupal\Core\Plugin\PluginWithFormsInterface::getFormClass().
PluginWithFormsTrait::hasFormClass public function Implements \Drupal\Core\Plugin\PluginWithFormsInterface::hasFormClass().
StringTranslationTrait::$stringTranslation protected property The string translation service. 4
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.