Skip to content

Commit c18721c

Browse files
authored
VACMS-13847: Create ContentReleaseStrategy plugin system. (#14160)
* VACMS-13847: Create ContentReleaseStrategy plugin system. * Adds strategy plugin system. * Expands tests, fixes issues from copypasta mistakes. * GitHubRepositoryDispatch stuff, tests, etc. * Adds LocalFilesystemBuildFile strategy plugin and tests. * Adds stuff to support watchdog_exception() call.
1 parent ee7c20c commit c18721c

32 files changed

+1459
-8
lines changed

config/sync/core.extension.yml

+1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ module:
238238
va_gov_build_trigger: 0
239239
va_gov_bulk: 0
240240
va_gov_clp: 0
241+
va_gov_content_release: 0
241242
va_gov_dashboards: 0
242243
va_gov_db: 0
243244
va_gov_entity_browser: 0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Drupal\va_gov_consumers\Exception;
4+
5+
/**
6+
* Exception thrown when GitHub repository dispatch fails.
7+
*/
8+
class GitHubRepositoryDispatchException extends \Exception {}

docroot/modules/custom/va_gov_consumers/src/GitHub/GitHubClient.php

+21-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Drupal\va_gov_consumers\GitHub;
44

5+
use Drupal\va_gov_consumers\Exception\GitHubRepositoryDispatchException;
56
use GuzzleHttp\ClientInterface as HttpClientInterface;
67
use Psr\Http\Message\ResponseInterface;
78

@@ -173,16 +174,32 @@ public function triggerWorkflow(string $workflowName, string $ref, array $params
173174
* {@inheritDoc}
174175
*/
175176
public function listWorkflowRuns(string $workflowName, array $params = []) : array {
176-
$response = $this->listWorkflowRunsRaw($workflowName, $params);
177-
$data = json_decode($response->getBody()->getContents(), TRUE);
178-
return $data;
177+
try {
178+
$response = $this->listWorkflowRunsRaw($workflowName, $params);
179+
if ($response->getStatusCode() !== 200) {
180+
throw new GitHubRepositoryDispatchException('Listing workflow runs failed with status code: ' . $response->getStatusCode());
181+
}
182+
$data = json_decode($response->getBody()->getContents(), TRUE);
183+
return $data;
184+
}
185+
catch (\Throwable $exception) {
186+
throw new GitHubRepositoryDispatchException('Listing workflow runs failed.', $exception->getCode(), $exception);
187+
}
179188
}
180189

181190
/**
182191
* {@inheritDoc}
183192
*/
184193
public function repositoryDispatchWorkflow(string $eventType, object $clientPayload = NULL) : void {
185-
$this->repositoryDispatchWorkflowRaw($eventType, $clientPayload);
194+
try {
195+
$response = $this->repositoryDispatchWorkflowRaw($eventType, $clientPayload);
196+
if ($response->getStatusCode() !== 204) {
197+
throw new GitHubRepositoryDispatchException('Repository dispatch failed with status code: ' . $response->getStatusCode());
198+
}
199+
}
200+
catch (\Throwable $exception) {
201+
throw new GitHubRepositoryDispatchException('Repository dispatch failed.', $exception->getCode(), $exception);
202+
}
186203
}
187204

188205
}

docroot/modules/custom/va_gov_consumers/src/GitHub/GitHubClientInterface.php

+6
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ public function triggerWorkflow(string $workflowName, string $ref, array $params
4343
* @param array $params
4444
* A list of named params to pass to the action as arguments. Keys should
4545
* match the action input names.
46+
*
47+
* @throws \Drupal\va_gov_consumers\Exception\GitHubRepositoryDispatchException
48+
* If listing workflow runs fails or returns an unexpected status code.
4649
*/
4750
public function listWorkflowRuns(string $workflowName, array $params = []) : array;
4851

@@ -53,6 +56,9 @@ public function listWorkflowRuns(string $workflowName, array $params = []) : arr
5356
* A custom webhook event name. Must be 100 characters or fewer.
5457
* @param object $clientPayload
5558
* Optional extra data to send as the payload with the dispatch.
59+
*
60+
* @throws \Drupal\va_gov_consumers\Exception\GitHubRepositoryDispatchException
61+
* If the repository dispatch fails or returns an unexpected status code.
5662
*/
5763
public function repositoryDispatchWorkflow(string $eventType, object $clientPayload = NULL) : void;
5864

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace Drupal\va_gov_content_release\Annotation;
4+
5+
use Drupal\Component\Annotation\Plugin;
6+
7+
/**
8+
* Defines the annotation object for content release strategy plugins.
9+
*
10+
* @see plugin_api
11+
* @see \Drupal\va_gov_content_release\Strategy\Plugin\StrategyPluginInterface
12+
* @see \Drupal\va_gov_content_release\Strategy\Plugin\StrategyPluginManager
13+
*
14+
* @Annotation
15+
*/
16+
class ContentReleaseStrategy extends Plugin {
17+
18+
/**
19+
* The plugin ID.
20+
*
21+
* @var string
22+
*/
23+
public $id;
24+
25+
/**
26+
* The human-readable name of the environemnt.
27+
*
28+
* @var \Drupal\Core\Annotation\Translation
29+
*/
30+
public $label;
31+
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Drupal\va_gov_content_release\Exception;
4+
5+
/**
6+
* Exception thrown when a content release is already in progress.
7+
*/
8+
class ContentReleaseInProgressException extends \Exception {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Drupal\va_gov_content_release\Exception;
4+
5+
/**
6+
* Exception thrown when GitHub repository dispatch fails.
7+
*/
8+
class GitHubRepositoryDispatchException extends \Exception {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Drupal\va_gov_content_release\Exception;
4+
5+
/**
6+
* Exception thrown when the strategy encounters an error and cannot continue.
7+
*/
8+
class StrategyErrorException extends \Exception {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Drupal\va_gov_content_release\Exception;
4+
5+
/**
6+
* Exception thrown when the strategy cannot be found.
7+
*/
8+
class UnknownStrategyException extends \Exception {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
namespace Drupal\va_gov_content_release\GitHub;
4+
5+
use Drupal\va_gov_consumers\GitHub\GitHubClientInterface;
6+
use Drupal\va_gov_content_release\Exception\ContentReleaseInProgressException;
7+
use Drupal\va_gov_content_release\Exception\GitHubRepositoryDispatchException;
8+
9+
/**
10+
* The GitHub repository dispatch service.
11+
*
12+
* This service is used to dispatch repository dispatch events to GitHub, to
13+
* check whether a current workflow is pending, and to make these operations
14+
* testable.
15+
*
16+
* @see \Drupal\va_gov_content_release\GitHub\GitHubRepositoryDispatchInterface
17+
*/
18+
class GitHubRepositoryDispatch implements GitHubRepositoryDispatchInterface {
19+
20+
/**
21+
* The GitHub client.
22+
*
23+
* @var \Drupal\va_gov_consumers\GitHub\GitHubClientInterface
24+
*/
25+
protected $client;
26+
27+
/**
28+
* Constructor.
29+
*
30+
* @param \Drupal\va_gov_consumers\GitHub\GitHubClientInterface $client
31+
* The GitHub client.
32+
*/
33+
public function __construct(GitHubClientInterface $client) {
34+
$this->client = $client;
35+
}
36+
37+
/**
38+
* Build parameters for determining whether a workflow is pending.
39+
*
40+
* @param int|null $time
41+
* The time to use for the 'created' parameter. Defaults to the current
42+
* time.
43+
*
44+
* @return array
45+
* The parameters.
46+
*/
47+
public function buildPendingWorkflowParams(int $time = NULL) : array {
48+
$time = $time ?? time();
49+
$sinceTimestamp = $time - (2 * 60 * 60);
50+
return [
51+
'status' => 'pending',
52+
'created' => '>=' . date('c', $sinceTimestamp),
53+
];
54+
}
55+
56+
/**
57+
* {@inheritDoc}
58+
*/
59+
public function dispatch() : void {
60+
try {
61+
if ($this->isPending()) {
62+
throw new ContentReleaseInProgressException('A workflow is already pending.');
63+
}
64+
$this->client->repositoryDispatchWorkflow(static::EVENT_TYPE);
65+
}
66+
catch (ContentReleaseInProgressException $exception) {
67+
throw $exception;
68+
}
69+
catch (\Throwable $throwable) {
70+
throw new GitHubRepositoryDispatchException('Repository dispatch failed.', $throwable->getCode(), $throwable);
71+
}
72+
}
73+
74+
/**
75+
* {@inheritDoc}
76+
*/
77+
public function isPending() : bool {
78+
try {
79+
$parameters = $this->buildPendingWorkflowParams();
80+
$workflowRuns = $this->client->listWorkflowRuns(static::EVENT_TYPE . '.yml', $parameters);
81+
return !empty($workflowRuns['total_count']) && $workflowRuns['total_count'] > 0;
82+
}
83+
catch (\Throwable $throwable) {
84+
throw new GitHubRepositoryDispatchException('Failed to get workflow runs.', $throwable->getCode(), $throwable);
85+
}
86+
}
87+
88+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace Drupal\va_gov_content_release\GitHub;
4+
5+
/**
6+
* An interface for the GitHub repository dispatch service.
7+
*
8+
* This service is used to dispatch repository dispatch events to GitHub, to
9+
* check whether a current workflow is pending, and to make these operations
10+
* testable.
11+
*
12+
* @see \Drupal\va_gov_content_release\GitHub\GitHubRepositoryDispatch
13+
*/
14+
interface GitHubRepositoryDispatchInterface {
15+
16+
// The event type for content release.
17+
const EVENT_TYPE = 'content-release';
18+
19+
/**
20+
* Dispatch a repository dispatch event to trigger content release.
21+
*
22+
* @throws \Drupal\va_gov_content_release\Exception\GitHubRepositoryDispatchException
23+
* If the repository dispatch fails.
24+
*/
25+
public function dispatch() : void;
26+
27+
/**
28+
* Check whether a workflow is pending.
29+
*
30+
* @return bool
31+
* TRUE if a workflow is pending, FALSE otherwise.
32+
*
33+
* @throws \Drupal\va_gov_content_release\Exception\GitHubRepositoryDispatchException
34+
* If the request fails.
35+
*/
36+
public function isPending() : bool;
37+
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Drupal\va_gov_content_release\Plugin\Strategy;
4+
5+
use Drupal\va_gov_content_release\Exception\StrategyErrorException;
6+
use Drupal\va_gov_content_release\Strategy\Plugin\StrategyPluginBase;
7+
8+
/**
9+
* Exception test strategy.
10+
*
11+
* This always throws an exception.
12+
*
13+
* @ContentReleaseStrategy(
14+
* id = "test_exception",
15+
* label = @Translation("Exception Test")
16+
* )
17+
*/
18+
class ExceptionTest extends StrategyPluginBase {
19+
20+
/**
21+
* {@inheritDoc}
22+
*/
23+
public function triggerContentRelease() : void {
24+
throw new StrategyErrorException('This is a test exception.');
25+
}
26+
27+
}

0 commit comments

Comments
 (0)