Failed Conditions
Push — master ( 5433f0...117895 )
by Alexander
01:52
created

ChangeLogCloneCommand::execute()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 77
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
dl 0
loc 77
ccs 0
cts 61
cp 0
rs 6.5755
c 0
b 0
f 0
cc 7
eloc 48
nc 7
nop 2
crap 56

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Api;
15
use chobie\Jira\Issue;
16
use ConsoleHelpers\ConsoleKit\Exception\CommandException;
17
use ConsoleHelpers\JiraCLI\Issue\ChangeLogIssueCloner;
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_key',
49
				InputArgument::REQUIRED,
50
				'Project key, 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->getLinkNames();
89
		}
90
91
		return $ret;
92
	}
93
94
	/**
95
	 * Returns possible link names.
96
	 *
97
	 * @return array
98
	 */
99
	protected function getLinkNames()
100
	{
101
		$ret = array();
102
		$response = $this->jiraApi->api(Api::REQUEST_GET, '/rest/api/2/issueLinkType', array(), true);
103
104
		foreach ( $response['issueLinkTypes'] as $link_type_data ) {
105
			$ret[] = $link_type_data['name'];
106
		}
107
108
		return $ret;
109
	}
110
111
	/**
112
	 * {@inheritdoc}
113
	 *
114
	 * @throws CommandException When no backportable issues were found.
115
	 */
116
	protected function execute(InputInterface $input, OutputInterface $output)
117
	{
118
		$project_key = $this->io->getArgument('project_key');
119
120
		if ( !in_array($project_key, $this->getProjectKeys()) ) {
121
			throw new CommandException('The project with "' . $project_key . '" key does\'t exist.');
122
		}
123
124
		$link_name = $this->io->getOption('link-name');
125
126
		if ( !in_array($link_name, $this->getLinkNames()) ) {
127
			throw new CommandException('The "' . $link_name . '" link name doesn\'t exist.');
128
		}
129
130
		$issue_key = $this->io->getArgument('issue_key');
131
		$issues = $this->issueCloner->getIssues(
132
			'key = ' . $issue_key,
133
			$link_name,
134
			ChangeLogIssueCloner::LINK_DIRECTION_OUTWARD
135
		);
136
		$issue_count = count($issues);
137
138
		if ( $issue_count !== 1 ) {
139
			throw new CommandException('The "' . $issue_key . '" not found.');
140
		}
141
142
		/** @var Issue[] $issue_pair */
143
		$issue_pair = reset($issues);
144
		$issue = $issue_pair[0];
145
		$linked_issue = $issue_pair[1];
146
147
		$issue_project = $issue->get('project');
148
149
		if ( $issue_project['key'] === $project_key ) {
150
			throw new CommandException('Creating of linked issue in same project is not supported.');
151
		}
152
153
		if ( is_object($linked_issue) ) {
154
			$this->io->writeln(sprintf(
155
				'The "<info>%s</info>" issue already has "<info>%s</info>" link to "<info>%s</info>" issue.',
156
				$issue->getKey(),
157
				$link_name,
158
				$linked_issue->getKey()
159
			));
160
161
			return;
162
		}
163
164
		$components = array();
165
		$project_components = $this->getProjectComponents($project_key);
166
167
		if ( $project_components ) {
1 ignored issue
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...
168
			$component_name = $this->io->choose(
169
				'Select linked issue component:',
170
				$project_components,
171
				'',
172
				'The component isn\'t valid'
173
			);
174
175
			$components[] = array_search($component_name, $project_components);
176
		}
177
178
		$linked_issue_key = $this->issueCloner->createLinkedIssue(
179
			$issue,
180
			$project_key,
181
			$link_name,
182
			ChangeLogIssueCloner::LINK_DIRECTION_OUTWARD,
183
			$components
184
		);
185
186
		$this->io->writeln(sprintf(
187
			'The "<info>%s</info>" issue now has "<info>%s</info>" link to "<info>%s</info>" issue.',
188
			$issue->getKey(),
189
			$link_name,
190
			$linked_issue_key
191
		));
192
	}
193
194
	/**
195
	 * Returns project components.
196
	 *
197
	 * @param string $project_key Project key.
198
	 *
199
	 * @return array
200
	 */
201
	protected function getProjectComponents($project_key)
202
	{
203
		$ret = array();
204
		$project_components = $this->jiraApi->getProjectComponents($project_key);
205
206
		foreach ( $project_components as $project_component_data ) {
0 ignored issues
show
Bug introduced by
The expression $project_components of type array|object<chobie\Jira\Api\Result>|false is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
207
			$ret[$project_component_data['id']] = $project_component_data['name'];
208
		}
209
210
		return $ret;
211
	}
212
213
}
214