Passed
Push — master ( d64961...dc496c )
by Tom
04:20
created

Step::parseNamedScriptLine()   A

Complexity

Conditions 6
Paths 12

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 7
nc 12
nop 3
dl 0
loc 10
ccs 5
cts 5
cp 1
crap 6
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
/* this file is part of pipelines */
4
5
namespace Ktomk\Pipelines\File\Pipeline;
6
7
use Ktomk\Pipelines\File\Artifacts;
8
use Ktomk\Pipelines\File\Dom\FileNode;
9
use Ktomk\Pipelines\File\Image;
10
use Ktomk\Pipelines\File\ParseException;
11
use Ktomk\Pipelines\File\Pipeline;
12
13
class Step implements FileNode
14
{
15
    /**
16
     * @var array
17
     */
18
    private $step;
19
20
    /**
21
     * @var int number of the step, starting at one
22
     */
23
    private $index;
24
25
    /**
26
     * @var Pipeline
27
     */
28
    private $pipeline;
29
30
    /**
31
     * @var array step environment variables
32
     *   BITBUCKET_PARALLEL_STEP - zero-based index of the current step in the group, e.g. 0, 1, 2, ...
33
     *   BITBUCKET_PARALLEL_STEP_COUNT - total number of steps in the group, e.g. 5.
34
     */
35
    private $env;
36
37
    /**
38
     * Step constructor.
39
     *
40
     * @param Pipeline $pipeline
41
     * @param int $index
42
     * @param array $step
43
     * @param array $env [optional] environment variables in array notation for the new step
44
     */
45 20
    public function __construct(Pipeline $pipeline, $index, array $step, array $env = array())
46
    {
47
        // quick validation: image name
48 20
        Image::validate($step);
49
50
        // quick validation: trigger
51 19
        $this->validateTrigger($step, (bool)$env);
52
53
        // quick validation: script + after-script
54 19
        $this->parseScript($step);
55 16
        $this->parseAfterScript($step);
56
57 16
        $this->pipeline = $pipeline;
58 16
        $this->index = $index;
59 16
        $this->step = $step;
60 16
        $this->env = $env;
61 16
    }
62
63
    /**
64
     * @throws ParseException
65
     *
66
     * @return null|Artifacts
67
     */
68 3
    public function getArtifacts()
69
    {
70 3
        return isset($this->step['artifacts'])
71 1
            ? new Artifacts($this->step['artifacts'])
72 3
            : null;
73
    }
74
75
    /**
76
     * @throws ParseException
77
     *
78
     * @return Image
79
     */
80 3
    public function getImage()
81
    {
82 3
        return isset($this->step['image'])
83 1
            ? new Image($this->step['image'])
84 3
            : $this->pipeline->getFile()->getImage();
85
    }
86
87
    /**
88
     * @return null|string
89
     */
90 3
    public function getName()
91
    {
92 3
        return isset($this->step['name'])
93 1
            ? (string)$this->step['name']
94 3
            : null;
95
    }
96
97
    /**
98
     * @return StepServices
99
     */
100 1
    public function getServices()
101
    {
102 1
        $services = isset($this->step['services']) ? $this->step['services'] : array();
103
104 1
        return new StepServices($this, $services);
105
    }
106
107
    /**
108
     * @return array|string[]
109
     */
110 2
    public function getScript()
111
    {
112 2
        return $this->step['script'];
113
    }
114
115
    /**
116
     * @return array|string[]
117
     */
118 1
    public function getAfterScript()
119
    {
120 1
        if (isset($this->step['after-script'])) {
121 1
            return $this->step['after-script'];
122
        }
123
124 1
        return array();
125
    }
126
127
    /**
128
     * @return bool
129
     */
130 1
    public function isManual()
131
    {
132 1
        if (0 === $this->index) {
133 1
            return false;
134
        }
135
136 1
        return (isset($this->step['trigger']) && 'manual' === $this->step['trigger']);
137
    }
138
139
    /**
140
     * Specify data which should be serialized to JSON
141
     *
142
     * @return array
143
     */
144 1
    public function jsonSerialize()
145
    {
146 1
        $image = $this->getImage();
147 1
        $image = null === $image ? '' : $image->jsonSerialize();
148
149
        return array(
150 1
            'name' => $this->getName(),
151 1
            'image' => $image,
152 1
            'script' => $this->getScript(),
153 1
            'artifacts' => $this->getArtifacts(),
154
        );
155
    }
156
157
    /**
158
     * @return int
159
     */
160 1
    public function getIndex()
161
    {
162 1
        return $this->index;
163
    }
164
165
    /**
166
     * @return Pipeline
167
     * @codeCoverageIgnore
168
     */
169
    public function getPipeline()
170
    {
171
        return $this->pipeline;
172
    }
173
174
    /**
175
     * @return array step container environment variables (e.g. parallel a step)
176
     */
177 1
    public function getEnv()
178
    {
179 1
        return $this->env;
180
    }
181
182
    /**
183
     * @return \Ktomk\Pipelines\File\File
184
     */
185 1
    public function getFile()
186
    {
187 1
        return $this->pipeline->getFile();
188
    }
189
190
    /**
191
     * validate step trigger (none, manual, automatic)
192
     *
193
     * @param array $array
194
     * @param bool $isParallelStep
195
     *
196
     * @return void
197
     */
198 19
    private function validateTrigger(array $array, $isParallelStep)
199
    {
200 19
        if (!array_key_exists('trigger', $array)) {
201 19
            return;
202
        }
203
204 2
        $trigger = $array['trigger'];
205 2
        if ($isParallelStep) {
206 1
            throw new ParseException("Unexpected property 'trigger' in parallel step");
207
        }
208
209 2
        if (!in_array($trigger, array('manual', 'automatic'), true)) {
210 1
            throw new ParseException("'trigger' expects either 'manual' or 'automatic'");
211
        }
212 2
    }
213
214
    /**
215
     * Parse a step script section
216
     *
217
     * @param array $step
218
     *
219
     * @throws ParseException
220
     *
221
     * @return void
222
     */
223 19
    private function parseScript(array $step)
224
    {
225 19
        if (!isset($step['script'])) {
226 1
            throw new ParseException("'step' requires a script");
227
        }
228 18
        $this->parseNamedScript('script', $step);
229 16
    }
230
231
    /**
232
     * @param array $step
233
     *
234
     * @return void
235
     */
236 16
    private function parseAfterScript(array $step)
237
    {
238 16
        if (isset($step['after-script'])) {
239 1
            $this->parseNamedScript('after-script', $step);
240
        }
241 16
    }
242
243
    /**
244
     * @param string $name
245
     * @param $script
246
     *
247
     * @return void
248
     */
249 18
    private function parseNamedScript($name, array $script)
250
    {
251 18
        if (!is_array($script[$name]) || !count($script[$name])) {
252 1
            throw new ParseException("'${name}' requires a list of commands");
253
        }
254
255
        foreach ($script[$name] as $index => $line) {
256
            $this->parseNamedScriptLine($name, $index, $line);
257
        }
258
    }
259
260
    /**
261
     * @param string $name
262
     * @param int $index
263
     * @param null|array|bool|float|int|string $line
264
     *
265
     * @return void
266
     */
267
    private function parseNamedScriptLine($name, $index, $line)
268
    {
269 17
        $standard = is_scalar($line) || null === $line;
270 17
        $pipe = is_array($line) && isset($line['pipe']) && is_string($line['pipe']);
271
272 17
        if (!($standard || $pipe)) {
273 1
            throw new ParseException(sprintf(
274 1
                "'%s' requires a list of commands, step #%d is not a command",
275
                $name,
276
                $index
277
            ));
278
        }
279 17
    }
280
}
281