Skip to content

Commit 83b8e57

Browse files
authored
MCLOUD-5968: PostDeployCest is red (magento#731)
1 parent 8d47050 commit 83b8e57

18 files changed

+724
-138
lines changed

config/scenario.xsd

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@
1616
<xs:complexType>
1717
<xs:choice maxOccurs="unbounded">
1818
<xs:element name="step" type="stepType" minOccurs="0" maxOccurs="unbounded"/>
19+
<xs:element name="onFail">
20+
<xs:complexType>
21+
<xs:choice>
22+
<xs:element name="action" type="actionType" minOccurs="0" maxOccurs="unbounded"/>
23+
</xs:choice>
24+
</xs:complexType>
25+
</xs:element>
1926
</xs:choice>
2027
</xs:complexType>
2128
</xs:element>
@@ -56,6 +63,13 @@
5663
<xs:attribute name="skip" type="xs:boolean"/>
5764
</xs:complexType>
5865

66+
<xs:complexType name="actionType">
67+
<xs:attribute name="name" type="xs:string" use="required"/>
68+
<xs:attribute name="type" type="phpClassName"/>
69+
<xs:attribute name="priority" type="xs:integer"/>
70+
<xs:attribute name="skip" type="xs:boolean"/>
71+
</xs:complexType>
72+
5973
<xs:simpleType name="phpClassName">
6074
<xs:annotation>
6175
<xs:documentation>

config/services.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
<service id="Magento\MagentoCloud\Step\StepException" autowire="false" />
5151
<service id="Magento\MagentoCloud\Step\ValidateConfiguration" autowire="false" />
5252
<service id="Magento\MagentoCloud\Step\Build\BackupData" autowire="false" />
53+
<service id="Magento\MagentoCloud\OnFail\Action\SkipAction" autowire="false" />
54+
<service id="Magento\MagentoCloud\OnFail\Action\ActionException" autowire="false" />
5355
<service id="Magento\MagentoCloud\Service\ServiceMismatchException" autowire="false" />
5456
<service id="Magento\MagentoCloud\Shell\Process" autowire="false" />
5557
<service id="Magento\MagentoCloud\Shell\ProcessException" autowire="false" />

scenario/deploy.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,7 @@
121121
</arguments>
122122
</step>
123123
<step name="disable-maintenance-mode" type="Magento\MagentoCloud\Step\DisableMaintenanceMode" priority="1300"/>
124+
<onFail>
125+
<action name="create-deploy-failed-flag" type="Magento\MagentoCloud\OnFail\Action\CreateDeployFailedFlag" priority="100"/>
126+
</onFail>
124127
</scenario>

src/OnFail/Action/ActionException.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\MagentoCloud\OnFail\Action;
9+
10+
use Magento\MagentoCloud\App\GenericException;
11+
12+
/**
13+
* Action exception.
14+
*/
15+
class ActionException extends GenericException
16+
{
17+
}

src/OnFail/Action/ActionInterface.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\MagentoCloud\OnFail\Action;
9+
10+
/**
11+
* Action represent small scenario action on fail such us create some flags, etc
12+
*/
13+
interface ActionInterface
14+
{
15+
/**
16+
* Executes the action.
17+
*
18+
* @return void
19+
* @throws ActionException
20+
*/
21+
public function execute(): void;
22+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\MagentoCloud\OnFail\Action;
9+
10+
use Magento\MagentoCloud\Filesystem\Flag\Manager as FlagManager;
11+
use Throwable;
12+
13+
/**
14+
* Creates deploy_is_failed flag if deploy is failed.
15+
*/
16+
class CreateDeployFailedFlag implements ActionInterface
17+
{
18+
/**
19+
* @var FlagManager
20+
*/
21+
private $flagManager;
22+
23+
public function __construct(FlagManager $flagManager)
24+
{
25+
$this->flagManager = $flagManager;
26+
}
27+
28+
/**
29+
* Creates .deploy_is_failed flag.
30+
*
31+
* {@inheritDoc}
32+
*/
33+
public function execute(): void
34+
{
35+
try {
36+
$this->flagManager->set(FlagManager::FLAG_DEPLOY_HOOK_IS_FAILED);
37+
} catch (Throwable $exception) {
38+
throw new ActionException(
39+
$exception->getMessage(),
40+
$exception->getCode(),
41+
$exception
42+
);
43+
}
44+
}
45+
}

src/OnFail/Action/SkipAction.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\MagentoCloud\OnFail\Action;
9+
10+
use Psr\Log\LoggerInterface;
11+
12+
/**
13+
* Class for skipped actions.
14+
* Logs the information about skipped actions.
15+
*/
16+
class SkipAction implements ActionInterface
17+
{
18+
/**
19+
* @var LoggerInterface
20+
*/
21+
private $logger;
22+
23+
/**
24+
* @var string
25+
*/
26+
private $actionName;
27+
28+
/**
29+
* @param LoggerInterface $logger
30+
* @param string $actionName
31+
*/
32+
public function __construct(LoggerInterface $logger, string $actionName)
33+
{
34+
$this->logger = $logger;
35+
$this->actionName = $actionName;
36+
}
37+
38+
/**
39+
* Logs the information about action skipping
40+
*
41+
* {@inheritDoc}
42+
*/
43+
public function execute(): void
44+
{
45+
$this->logger->info(sprintf('Action "%s" was skipped', $this->actionName));
46+
}
47+
}

src/Scenario/Collector/Action.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\MagentoCloud\Scenario\Collector;
9+
10+
/**
11+
* Collects action data
12+
*/
13+
class Action
14+
{
15+
/**
16+
* Collect action data
17+
*
18+
* @param array $action
19+
* @return array
20+
*/
21+
public function collect(array $action): array
22+
{
23+
$actionData = [
24+
'name' => $action['@name'],
25+
'type' => $action['@type'] ?? '',
26+
'skip' => isset($action['@skip']) && $action['@skip'] === 'true',
27+
];
28+
29+
if (isset($action['@priority'])) {
30+
$actionData['priority'] = (int)$action['@priority'];
31+
}
32+
33+
return $actionData;
34+
}
35+
}

src/Scenario/Merger.php

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Magento\MagentoCloud\Scenario\Collector\Scenario;
1111
use Magento\MagentoCloud\Scenario\Collector\Step;
1212
use Magento\MagentoCloud\Scenario\Collector\Step as StepCollector;
13+
use Magento\MagentoCloud\Scenario\Collector\Action as ActionCollector;
1314
use Magento\MagentoCloud\Scenario\Exception\ValidationException;
1415

1516
/**
@@ -27,15 +28,22 @@ class Merger
2728
*/
2829
private $stepCollector;
2930

31+
/**
32+
* @var ActionCollector
33+
*/
34+
private $actionCollector;
35+
3036
/**
3137
* @var Scenario
3238
*/
3339
private $scenarioCollector;
3440

3541
/**
42+
* Required arguments for steps and actions
43+
*
3644
* @var array
3745
*/
38-
private static $stepRequiredArgs = [
46+
private static $requiredArgs = [
3947
'@name',
4048
'@priority',
4149
'@type'
@@ -44,63 +52,98 @@ class Merger
4452
/**
4553
* @param Resolver $resolver
4654
* @param StepCollector $stepCollector
55+
* @param ActionCollector $actionCollector
4756
* @param Scenario $scenarioCollector
4857
*/
49-
public function __construct(Resolver $resolver, StepCollector $stepCollector, Scenario $scenarioCollector)
50-
{
58+
public function __construct(
59+
Resolver $resolver,
60+
StepCollector $stepCollector,
61+
ActionCollector $actionCollector,
62+
Scenario $scenarioCollector
63+
) {
5164
$this->resolver = $resolver;
5265
$this->stepCollector = $stepCollector;
66+
$this->actionCollector = $actionCollector;
5367
$this->scenarioCollector = $scenarioCollector;
5468
}
5569

5670
/**
57-
* Merge an array of scenarios
71+
* Merge an array of scenarios.
5872
*
5973
* @param array $scenarios
6074
* @return array
6175
* @throws ValidationException
6276
*/
6377
public function merge(array $scenarios): array
6478
{
65-
$data = [];
79+
$data = [
80+
'steps' => [],
81+
'actions' => [],
82+
];
6683

6784
foreach ($scenarios as $scenario) {
6885
$scenarioData = $this->scenarioCollector->collect($scenario);
6986
if (!isset($scenarioData['step'])) {
7087
throw new ValidationException(sprintf('Steps aren\'t exist in "%s" file', $scenario));
7188
}
7289

73-
$steps = is_array(reset($scenarioData['step'])) ? $scenarioData['step'] : [$scenarioData['step']];
90+
$steps = $this->normalizeItems($scenarioData['step']);
7491

7592
foreach ($steps as $step) {
76-
$this->validateStep($step);
93+
$this->validate($step);
7794

78-
$data[$step['@name']] = array_replace_recursive(
79-
$data[$step['@name']] ?? [],
95+
$data['steps'][$step['@name']] = array_replace_recursive(
96+
$data['steps'][$step['@name']] ?? [],
8097
$this->stepCollector->collect($step)
8198
);
8299
}
100+
101+
$actions = isset($scenarioData['onFail']['action'])
102+
? $this->normalizeItems($scenarioData['onFail']['action'])
103+
: [];
104+
105+
foreach ($actions as $action) {
106+
$this->validate($action);
107+
108+
$data['actions'][$action['@name']] = array_replace_recursive(
109+
$data['actions'][$action['@name']] ?? [],
110+
$this->actionCollector->collect($action)
111+
);
112+
}
83113
}
84114

85115
return $this->resolver->resolve($data);
86116
}
87117

118+
/**
119+
* Normalizes items list.
120+
*
121+
* The xml parser can return a list of items or one single item from a xml file.
122+
* This method checks the data and make the list of one item if the parser returned only one item.
123+
*
124+
* @param array $items
125+
* @return array
126+
*/
127+
private function normalizeItems(array $items): array
128+
{
129+
return is_array(reset($items)) ? $items : [$items];
130+
}
131+
88132
/**
89133
* Validates if exists all required attributes.
90134
*
91-
* @param array $step
135+
* @param array $item
92136
* @throws ValidationException
93137
* @return void
94138
*/
95-
private function validateStep(array $step): void
139+
private function validate(array $item): void
96140
{
97-
$isSkipped = isset($step['@skip']) && $step['@skip'] === 'true';
98-
99-
$requiredAttributes = $isSkipped ? ['@name'] : self::$stepRequiredArgs;
141+
$isSkipped = isset($item['@skip']) && $item['@skip'] === 'true';
142+
$requiredAttributes = $isSkipped ? ['@name'] : self::$requiredArgs;
100143

101-
if ($missedArgs = array_diff($requiredAttributes, array_keys($step))) {
144+
if ($missedArgs = array_diff($requiredAttributes, array_keys($item))) {
102145
throw new ValidationException(sprintf(
103-
'Argument(s) "%s" are missed from step',
146+
'Argument(s) "%s" are missed from item',
104147
implode(', ', $missedArgs)
105148
));
106149
}

0 commit comments

Comments
 (0)