Failed Conditions
Push — master ( 829e1a...df917c )
by Alexander
01:42
created

ChangeLogCloneCommand::expandProjectKeys()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 7
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 14
ccs 0
cts 7
cp 0
crap 12
rs 10
1
<?php
2
/**
3
 * This file is part of the Jira-CLI library.
4
 * For the full copyright and license information, please view
5
 * the LICENSE file that was distributed with this source code.
6
 *
7
 * @copyright Alexander Obuhovich <[email protected]>
8
 * @link      https://github.com/console-helpers/jira-cli
9
 */
10
11
namespace ConsoleHelpers\JiraCLI\Command;
12
13
14
use chobie\Jira\Issue;
15
use ConsoleHelpers\ConsoleKit\Exception\CommandException;
16
use ConsoleHelpers\JiraCLI\Issue\ChangeLogIssueCloner;
17
use ConsoleHelpers\JiraCLI\JiraApi;
18
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
19
use Symfony\Component\Console\Input\InputArgument;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
22
use Symfony\Component\Console\Output\OutputInterface;
23
24
class ChangeLogCloneCommand extends AbstractCommand
25
{
26
27
	/**
28
	 * Issue cloner.
29
	 *
30
	 * @var ChangeLogIssueCloner
31
	 */
32
	protected $issueCloner;
33
34
	/**
35
	 * {@inheritdoc}
36
	 */
37
	protected function configure()
38
	{
39
		$this
40
			->setName('changelog-clone')
41
			->setDescription('Clones issue for changelog into another project')
42
			->addArgument(
43
				'issue_key',
44
				InputArgument::REQUIRED,
45
				'Issue key, e.g. <comment>JRA-1234</comment>'
46
			)
47
			->addArgument(
48
				'project_keys',
49
				InputArgument::REQUIRED | InputArgument::IS_ARRAY,
50
				'Project keys, e.g. <comment>PRJ</comment>'
51
			)
52
			->addOption(
53
				'link-name',
54
				null,
55
				InputOption::VALUE_REQUIRED,
56
				'Link name between issues',
57
				'Blocks'
58
			);
59
	}
60
61
	/**
62
	 * Prepare dependencies.
63
	 *
64
	 * @return void
65
	 */
66
	protected function prepareDependencies()
67
	{
68
		parent::prepareDependencies();
69
70
		$container = $this->getContainer();
71
72
		$this->issueCloner = $container['changelog_issue_cloner'];
73
	}
74
75
	/**
76
	 * Return possible values for the named option
77
	 *
78
	 * @param string            $optionName Option name.
79
	 * @param CompletionContext $context    Completion context.
80
	 *
81
	 * @return array
82
	 */
83
	public function completeOptionValues($optionName, CompletionContext $context)
84
	{
85
		$ret = parent::completeOptionValues($optionName, $context);
86
87
		if ( $optionName === 'link-name' ) {
88
			return $this->jiraApi->getIssueLinkTypeNames();
89
		}
90
91
		return $ret;
92
	}
93
94
	/**
95
	 * {@inheritdoc}
96
	 *
97
	 * @throws CommandException When no backportable issues were found.
98
	 */
99
	protected function execute(InputInterface $input, OutputInterface $output)
100
	{
101
		$issue_key = $this->io->getArgument('issue_key');
102
		$link_name = $this->io->getOption('link-name');
103
104
		if ( !in_array($link_name, $this->jiraApi->getIssueLinkTypeNames()) ) {
105
			throw new CommandException('The "' . $link_name . '" link name doesn\'t exist.');
106
		}
107
108
		$project_keys = $this->expandProjectKeys($this->io->getArgument('project_keys'));
0 ignored issues
show
Bug introduced by
It seems like $this->io->getArgument('project_keys') can also be of type null and string; however, parameter $project_keys of ConsoleHelpers\JiraCLI\C...nd::expandProjectKeys() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

108
		$project_keys = $this->expandProjectKeys(/** @scrutinizer ignore-type */ $this->io->getArgument('project_keys'));
Loading history...
109
		$non_existing_projects = array_diff($project_keys, $this->jiraApi->getProjectKeys());
110
111
		if ( $non_existing_projects ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $non_existing_projects of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
112
			throw new CommandException(
113
				'These projects doesn\'t exist: "' . implode('", "', $non_existing_projects) . '".'
114
			);
115
		}
116
117
		$issues = $this->issueCloner->getIssues(
118
			'key = ' . $issue_key,
0 ignored issues
show
Bug introduced by
Are you sure $issue_key of type null|string|string[] can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

118
			'key = ' . /** @scrutinizer ignore-type */ $issue_key,
Loading history...
119
			$link_name,
0 ignored issues
show
Bug introduced by
It seems like $link_name can also be of type string[]; however, parameter $link_name of ConsoleHelpers\JiraCLI\I...ssueCloner::getIssues() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

119
			/** @scrutinizer ignore-type */ $link_name,
Loading history...
120
			ChangeLogIssueCloner::LINK_DIRECTION_OUTWARD,
121
			$project_keys
122
		);
123
		$issue_count = count($issues);
124
125
		if ( !$issue_count ) {
126
			throw new CommandException('The "' . $issue_key . '" issue not found.');
127
		}
128
129
		foreach ( $issues as $issue_pair ) {
130
			/** @var Issue $issue */
131
			/** @var Issue $linked_issue */
132
			list($issue, $linked_issue, $link_project_key) = $issue_pair;
133
134
			$issue_project = $issue->get('project');
135
136
			if ( $issue_project['key'] === $link_project_key ) {
137
				throw new CommandException('Creating of linked issue in same project is not supported.');
138
			}
139
140
			if ( is_object($linked_issue) ) {
141
				$this->io->writeln(sprintf(
142
					'The "<info>%s</info>" issue already has "<info>%s</info>" link to "<info>%s</info>" issue.',
143
					$issue->getKey(),
144
					$link_name,
0 ignored issues
show
Bug introduced by
It seems like $link_name can also be of type string[]; however, parameter $values of sprintf() does only seem to accept double|integer|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

144
					/** @scrutinizer ignore-type */ $link_name,
Loading history...
145
					$linked_issue->getKey()
146
				));
147
148
				continue;
149
			}
150
151
			$components = array();
152
			$project_components = $this->jiraApi->getProjectComponentMapping(
153
				$link_project_key,
154
				JiraApi::CACHE_DURATION_ONE_MONTH
155
			);
156
157
			if ( $project_components ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $project_components of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
158
				$component_name = $this->io->choose(
159
					'Select linked issue component in "' . $link_project_key . '" project:',
160
					$project_components,
161
					'',
162
					'The component isn\'t valid'
163
				);
164
165
				$components[] = array_search($component_name, $project_components);
166
			}
167
168
			$start = microtime(true);
169
170
			$linked_issue_key = $this->issueCloner->createLinkedIssue(
171
				$issue,
172
				$link_project_key,
173
				$link_name,
0 ignored issues
show
Bug introduced by
It seems like $link_name can also be of type string[]; however, parameter $link_name of ConsoleHelpers\JiraCLI\I...er::createLinkedIssue() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

173
				/** @scrutinizer ignore-type */ $link_name,
Loading history...
174
				ChangeLogIssueCloner::LINK_DIRECTION_OUTWARD,
175
				$components
176
			);
177
178
			$this->statistics[] = sprintf(
179
				'Issue %s creation time: %ss',
180
				$linked_issue_key,
181
				round(microtime(true) - $start, 3)
182
			);
183
184
			$this->io->writeln(sprintf(
185
				'The "<info>%s</info>" issue now has "<info>%s</info>" link to "<info>%s</info>" issue.',
186
				$issue->getKey(),
187
				$link_name,
188
				$linked_issue_key
189
			));
190
		}
191
192
		$this->showStatistics();
193
	}
194
195
	/**
196
	 * Expands project keys.
197
	 *
198
	 * @param array $project_keys Project keys.
199
	 *
200
	 * @return array
201
	 */
202
	protected function expandProjectKeys(array $project_keys)
203
	{
204
		$ret = array();
205
206
		foreach ( $project_keys as $project_key ) {
207
			if ( strpos($project_key, ',') === false ) {
208
				$ret[] = $project_key;
209
			}
210
			else {
211
				$ret = array_merge($ret, explode(',', $project_key));
212
			}
213
		}
214
215
		return $ret;
216
	}
217
218
}
219