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 ) { |
|
|
|
|
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 ) { |
|
|
|
|
207
|
|
|
$ret[$project_component_data['id']] = $project_component_data['name']; |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
return $ret; |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
} |
214
|
|
|
|
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.