9 Update Bugzilla dependencies (Dependencies/Blockers/Duplicates and Related),
10 transfering those relationships over to any matching JIRA issues.
18 Andrew DeFaria <Andrew@ClearSCM.com>
26 Thu Mar 20 10:11:53 PDT 2014
36 $ jiradep.pl [-bugzillaserver <bugshost>] [-login <login email>]
37 [-jiraserver <server>]
38 [-username <username>] [-password <password>]
39 [-bugids bugid,bugid,... | -file <filename>]
40 [-[no]exec] [-linkbugzilla] [-relinkbugzilla]
41 [-verbose] [-help] [-usage]
45 -v|erbose: Display progress output
46 -he|lp: Display full help
47 -usa|ge: Display usage
48 -[no]e|xec: Whether or not to update Bugilla. -noexec says only
49 tell me what you would have updated.
50 -use|rname: Username to log into JIRA with (Default: jira-admin)
51 -p|assword: Password to log into JIRA with (Default: jira-admin's
53 -bugzillaserver: Machine where Bugzilla lives (Default: bugs-dev)
54 -jiraserver: Machine where Jira lives (Default: jira-dev)
55 -bugi|ds: Comma separated list of BugIDs to process
56 -f|ile: File of BugIDs, one per line
57 -linkbugzilla: If specified and we find that we cannot translate
58 a Bugzilla Bud ID to a JIRA Issue then create a
59 remote link for the Bugzilla Bug. (Default:
60 do not create Bugzilla remote links).
61 -relinkbugzilla: Scan current Remote Bugzilla links and if there
62 exists a corresponding JIRA issue, remove the
63 Remote Bugzilla link and make it a JIRA Issue
65 -jiradbhost: Host name of the machine where the MySQL jiradb
66 database is located (Default: cm-db-ldev01)
70 This script will process all BugIDs translating them into JIRA Issues, if
71 applicable. It will then determine the relationships of this BugID in Bugzilla -
72 what it blocks, what it depends on, if it's a duplicate of another bug or if
73 it has any related links. Those too will be translated to JIRA issues, again,
74 if applicable. Then the JIRA issue will be updates to reflect these
77 Note that it's not known at this time what to do for situations where BugIDs
78 cannot be translated into JIRA issues if such Bugzilla bugs have not yet been
79 migrated to JIRA. There's a though to simply make a Bugzilla Link but we will
80 need to keep that in mind and when we import the next project to JIRA these
81 old, no longer used Bugzilla Links should be converted to their corresponding
82 JIRA issue. Perhaps this script can do that too.
87 use lib "$FindBin::Bin/lib";
104 bugzillaserver => $ENV{BUGZILLASERVER} || 'bugs-dev',
105 jiraserver => $ENV{JIRASERVER} || 'jira-dev',
106 jiradbhost => $ENV{JIRA_DB_HOST} || 'cm-db-ldev01',
107 username => 'jira-admin',
108 password => 'jira-admin',
109 usage => sub { pod2usage },
110 help => sub { pod2usage (-verbose => 2)},
111 verbose => sub { set_verbose },
113 usage => sub { pod2usage },
114 help => sub { pod2usage (-verbose => 2)},
119 my %relationshipMap = (
120 Blocks => 'Dependencies Linked',
121 Duplicate => 'Duplicates Linked',
122 Related => 'Related Linked',
125 sub callLink ($$$$) {
126 my ($from, $type, $to, $counter) = @_;
130 if ($from =~ /^\d+/) {
131 if ($type eq 'Blocks') {
132 $bugzillaType = 'is blocked by (Bugzilla)';
133 } elsif ($type eq 'Duplicate') {
134 $bugzillaType = 'duplicate (Bugzilla)';
135 } elsif ($type eq 'Related') {
136 $bugzillaType = 'related (Bugzilla)';
138 } elsif ($to =~ /^\d+/) {
139 if ($type eq 'Blocks') {
140 $bugzillaType = 'blocks (Bugzilla)';
141 } elsif ($type eq 'Duplicate') {
142 $bugzillaType = 'duplicate (Bugzilla)';
143 } elsif ($type eq 'Related') {
144 $bugzillaType = 'related (Bugzilla)';
150 if ($from =~ /^\d+/ && $to =~ /^\d+/) {
151 $total{'Skipped Bugzilla Links'}++;
153 return "Refusing to link because both from ($from) and to ($to) links are still a Bugzilla link";
154 } elsif ($from =~ /^\d+/) {
155 if ($opts{linkbugzilla}) {
156 my $result = addRemoteLink $from, $bugzillaType, $to;
158 $total{'Bugzilla Links'}++ unless $result;
161 return "Created remote $type link between Issue $to and Bug $from";
166 $total{'Skipped Bugzilla Links'}++;
168 return "Refusing to link because from link ($from) is still a Bugzilla link";
170 } elsif ($to =~ /^\d+/) {
171 if ($opts{linkbugzilla}) {
172 my $result = addRemoteLink $to, $bugzillaType, $from;
174 $total{'Bugzilla Links'}++ unless $result;
176 if (!defined $result) {
180 return "Created remote $type link between Issue $from and Bug $to";
185 $total{'Skipped Bugzilla Links'}++;
187 return "Refusing to link because to link ($to) is still a Bugzilla link";
191 my $result = linkIssues $from, $type, $to;
195 if ($result =~ /^Unable/) {
196 $total{'Link Failures'}++;
197 } elsif ($result =~ /^Link made/) {
198 $total{'Links made'}++;
199 } elsif ($result =~ /^Would have linked/) {
200 $total{'Links would be made'}++;
206 sub relinkBugzilla (@) {
209 my %mapRelationships = (
210 'blocks (Bugzilla)' => 'Blocks',
211 'is blocked by (Bugzilla)' => 'Blocks',
212 'duplicates (Bugzilla)' => 'Duplicates',
213 'is duplicated by (Bugzilla)' => 'Duplicates',
215 'Bugzilla blocks' => 'Blocks',
216 'Bugzilla is blocked by' => 'Blocks',
217 'Bugzilla duplicates' => 'Duplicates',
218 'Bugzilla is duplicated by' => 'Duplicates',
221 @bugids = getRemoteLinks unless @bugids;
223 for my $bugid (@bugids) {
224 $total{'Remote Links Scanned'}++;
226 my $links = findRemoteLinkByBugID $bugid;
228 my $jirafrom = findIssue ($bugid);
230 next if $jirafrom !~ /^[A-Z]{1,5}-\d+$/;
235 # Found a link to JIRA. Remove remotelink and make an issuelink
236 if ($mapRelationships{$link{relationship}}) {
237 my ($fromIssue, $toIssue);
239 if ($link{relationship} =~ / by/) {
240 $fromIssue = $jirafrom;
241 $toIssue = $link{issue};
243 $fromIssue = $link{issue};
244 $toIssue = $jirafrom;
247 my $status = promoteBug2JIRAIssue $bugid, $fromIssue, $toIssue,
248 $mapRelationships{$link{relationship}};
250 $log->err ($status) if $status =~ /Unable to link/;
252 $log->err ("Unable to handle relationships of type $link{relationship}");
261 my $startTime = time;
284 open my $file, '<', $opts{file}
285 or $log->err ("Unable to open $opts{file} - $!", 1);
287 $opts{bugids} = [<$file>];
289 chomp @{$opts{bugids}};
293 push @bugids, (split /,/, join (',', $_)) for (@{$opts{bugids}});
295 $opts{bugids} = [@bugids];
298 pod2usage 'Must specify -bugids <bugid>[,<bugid>,...] or -file <filename>'
299 unless ($opts{bugids} > 0 or $opts{relinkbugzilla});
301 openBugzilla $opts{bugzillaserver}
302 or $log->err ("Unable to connect to $opts{bugzillaserver}", 1);
304 Connect2JIRA ($opts{username}, $opts{password}, $opts{jiraserver})
305 or $log->err ("Unable to connect to $opts{jiraserver}", 1);
307 if ($opts{relinkbugzilla}) {
308 unless (@{$opts{bugids}}) {
311 relinkBugzilla $_ for @{$opts{bugids}}
314 Stats (\%total, $log);
321 # The 'Blocks' IssueLinkType has two types of relationships in it - both
322 # blocks and dependson. Since JIRA has only one type - Blocks - we take
323 # the $dependson and flip the from and to.
324 my $blocks = getBlockers @{$opts{bugids}};
325 my $dependson = getDependencies @{$opts{bugids}};
327 # Now merge them - we did it backwards!
328 for my $fromLink (keys %$dependson) {
329 for my $toLink (@{$dependson->{$fromLink}}) {
330 push @{$relationships{Blocks}{$toLink}}, $fromLink;
334 #%{$relationships{Blocks}} = %$dependson;
336 for my $fromLink (keys %$blocks) {
337 # Check to see if we already have the reverse of this link
338 for my $toLink (@{$blocks->{$fromLink}}) {
339 unless (grep {$toLink eq $_} keys %{$relationships{Blocks}}) {
340 push @{$relationships{Blocks}{$fromLink}}, $toLink;
345 $relationships{Duplicate} = getDuplicates @{$opts{bugids}};
346 $relationships{Relates} = getRelated @{$opts{bugids}};
348 # Process relationships (social programming... ;-)
349 $log->msg ("Processing relationships");
351 for my $type (keys %relationshipMap) {
352 for my $from (keys %{$relationships{$type}}) {
353 for my $to (@{$relationships{$type}{$from}}) {
354 $total{'Relationships processed'}++;
356 my $result = callLink $from, $type, $to, $relationshipMap{$type};
358 $log->msg ($result) if $result;
363 display_duration $startTime, $log;
365 Stats (\%total, $log) unless $opts{quiet};