Bug 385415: Bugs marked as duplicate or moved to another installation… · gzgithub/bugzilla@ff222ad · GitHub
Skip to content

Commit ff222ad

Browse files
author
lpsolit%gmail.com
committed
Bug 385415: Bugs marked as duplicate or moved to another installation always go to the RESOLVED state, even if the workflow has RESOLVED excluded from it (or if this bug status has been removed or renamed). Some major problems related to the workflow when upgrading or installing 3.1 are also fixed here - Patch by Frédéric Buclin <LpSolit@gmail.com> r/a=mkanat
1 parent 012d45a commit ff222ad

12 files changed

Lines changed: 217 additions & 84 deletions

File tree

‎Bugzilla/Bug.pm‎

Lines changed: 4 additions & 4 deletions

‎Bugzilla/Config/BugChange.pm‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,34 @@ package Bugzilla::Config::BugChange;
3434
use strict;
3535

3636
use Bugzilla::Config::Common;
37+
use Bugzilla::Status;
3738

3839
$Bugzilla::Config::BugChange::sortkey = "03";
3940

4041
sub get_param_list {
4142
my $class = shift;
43+
44+
# Hardcoded bug statuses which existed before Bugzilla 3.1.
45+
my @closed_bug_statuses = ('RESOLVED', 'VERIFIED', 'CLOSED');
46+
47+
# If we are upgrading from 3.0 or older, bug statuses are not customisable
48+
# and bug_status.is_open is not yet defined (hence the eval), so we use
49+
# the bug statuses above as they are still hardcoded.
50+
eval {
51+
my @current_closed_states = map {$_->name} Bugzilla::Status::closed_bug_statuses();
52+
# If no closed state was found, use the default list above.
53+
@closed_bug_statuses = @current_closed_states if scalar(@current_closed_states);
54+
};
55+
4256
my @param_list = (
57+
{
58+
name => 'duplicate_or_move_bug_status',
59+
type => 's',
60+
choices => \@closed_bug_statuses,
61+
default => $closed_bug_statuses[0],
62+
checker => \&check_bug_status
63+
},
64+
4365
{
4466
name => 'letsubmitterchoosepriority',
4567
type => 'b',

‎Bugzilla/Config/Common.pm‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use Bugzilla::Util;
4040
use Bugzilla::Constants;
4141
use Bugzilla::Field;
4242
use Bugzilla::Group;
43+
use Bugzilla::Status;
4344

4445
use base qw(Exporter);
4546
@Bugzilla::Config::Common::EXPORT =
@@ -48,7 +49,7 @@ use base qw(Exporter);
4849
check_opsys check_shadowdb check_urlbase check_webdotbase
4950
check_netmask check_user_verify_class check_image_converter
5051
check_languages check_mail_delivery_method check_notification
51-
check_timezone check_utf8
52+
check_timezone check_utf8 check_bug_status
5253
);
5354

5455
# Checking functions for the various values
@@ -166,6 +167,15 @@ sub check_opsys {
166167
return "";
167168
}
168169

170+
sub check_bug_status {
171+
my $bug_status = shift;
172+
my @closed_bug_statuses = map {$_->name} Bugzilla::Status::closed_bug_statuses();
173+
if (lsearch(\@closed_bug_statuses, $bug_status) < 0) {
174+
return "Must be a valid closed status: one of " . join(', ', @closed_bug_statuses);
175+
}
176+
return "";
177+
}
178+
169179
sub check_group {
170180
my $group_name = shift;
171181
return "" unless $group_name;

‎Bugzilla/Install/DB.pm‎

Lines changed: 85 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -2783,85 +2783,102 @@ sub _initialize_workflow {
27832783
my $old_params = shift;
27842784
my $dbh = Bugzilla->dbh;
27852785

2786-
if (!$dbh->bz_column_info('bug_status', 'is_open')) {
2787-
$dbh->bz_add_column('bug_status', 'is_open',
2788-
{TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'TRUE'});
2789-
2790-
# Till now, bug statuses were not customizable. Nevertheless, local
2791-
# changes are possible and so we will try to respect these changes.
2792-
# This means: get the status of bugs having a resolution different from ''
2793-
# and mark these statuses as 'closed', even if some of these statuses are
2794-
# expected to be open statuses. Bug statuses we have no information about
2795-
# are left as 'open'.
2796-
my @statuses =
2797-
@{$dbh->selectcol_arrayref('SELECT DISTINCT bug_status FROM bugs
2798-
WHERE resolution != ?', undef, '')};
2786+
$dbh->bz_add_column('bug_status', 'is_open',
2787+
{TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'TRUE'});
27992788

2800-
# Append the default list of closed statuses. Duplicated statuses don't hurt.
2801-
@statuses = map {$dbh->quote($_)} (@statuses, qw(RESOLVED VERIFIED CLOSED));
2789+
# Till now, bug statuses were not customizable. Nevertheless, local
2790+
# changes are possible and so we will try to respect these changes.
2791+
# This means: get the status of bugs having a resolution different from ''
2792+
# and mark these statuses as 'closed', even if some of these statuses are
2793+
# expected to be open statuses. Bug statuses we have no information about
2794+
# are left as 'open'.
2795+
my @closed_statuses =
2796+
@{$dbh->selectcol_arrayref('SELECT DISTINCT bug_status FROM bugs
2797+
WHERE resolution != ?', undef, '')};
2798+
2799+
# Append the default list of closed statuses *unless* we detect at least
2800+
# one closed state in the DB (i.e. with is_open = 0). This would mean that
2801+
# the DB has already been updated at least once and maybe the admin decided
2802+
# that e.g. 'RESOLVED' is now an open state, in which case we don't want to
2803+
# override this attribute. At least one bug status has to be a closed state
2804+
# anyway (due to the 'duplicate_or_move_bug_status' parameter) so it's safe
2805+
# to use this criteria.
2806+
my $num_closed_states = $dbh->selectrow_array('SELECT COUNT(*) FROM bug_status
2807+
WHERE is_open = 0');
2808+
2809+
if (!$num_closed_states) {
2810+
@closed_statuses =
2811+
map {$dbh->quote($_)} (@closed_statuses, qw(RESOLVED VERIFIED CLOSED));
28022812

28032813
print "Marking closed bug statuses as such...\n";
28042814
$dbh->do('UPDATE bug_status SET is_open = 0 WHERE value IN (' .
2805-
join(', ', @statuses) . ')');
2815+
join(', ', @closed_statuses) . ')');
28062816
}
28072817

28082818
# Populate the status_workflow table. We do nothing if the table already
28092819
# has entries. If all bug status transitions have been deleted, the
28102820
# workflow will be restored to its default schema.
28112821
my $count = $dbh->selectrow_array('SELECT COUNT(*) FROM status_workflow');
2812-
return if $count;
2813-
2814-
my $create = $old_params->{'commentoncreate'};
2815-
my $confirm = $old_params->{'commentonconfirm'};
2816-
my $accept = $old_params->{'commentonaccept'};
2817-
my $resolve = $old_params->{'commentonresolve'};
2818-
my $verify = $old_params->{'commentonverify'};
2819-
my $close = $old_params->{'commentonclose'};
2820-
my $reopen = $old_params->{'commentonreopen'};
2821-
# This was till recently the only way to get back to NEW for
2822-
# confirmed bugs, so we use this parameter here.
2823-
my $reassign = $old_params->{'commentonreassign'};
2824-
2825-
# This is the default workflow.
2826-
my @workflow = ([undef, 'UNCONFIRMED', $create],
2827-
[undef, 'NEW', $create],
2828-
[undef, 'ASSIGNED', $create],
2829-
['UNCONFIRMED', 'NEW', $confirm],
2830-
['UNCONFIRMED', 'ASSIGNED', $accept],
2831-
['UNCONFIRMED', 'RESOLVED', $resolve],
2832-
['NEW', 'ASSIGNED', $accept],
2833-
['NEW', 'RESOLVED', $resolve],
2834-
['ASSIGNED', 'NEW', $reassign],
2835-
['ASSIGNED', 'RESOLVED', $resolve],
2836-
['REOPENED', 'NEW', $reassign],
2837-
['REOPENED', 'ASSIGNED', $accept],
2838-
['REOPENED', 'RESOLVED', $resolve],
2839-
['RESOLVED', 'UNCONFIRMED', $reopen],
2840-
['RESOLVED', 'REOPENED', $reopen],
2841-
['RESOLVED', 'VERIFIED', $verify],
2842-
['RESOLVED', 'CLOSED', $close],
2843-
['VERIFIED', 'UNCONFIRMED', $reopen],
2844-
['VERIFIED', 'REOPENED', $reopen],
2845-
['VERIFIED', 'CLOSED', $close],
2846-
['CLOSED', 'UNCONFIRMED', $reopen],
2847-
['CLOSED', 'REOPENED', $reopen]);
2848-
2849-
print "Now filling the 'status_workflow' table with valid bug status transitions...\n";
2850-
my $sth_select = $dbh->prepare('SELECT id FROM bug_status WHERE value = ?');
2851-
my $sth = $dbh->prepare('INSERT INTO status_workflow (old_status, new_status,
2852-
require_comment) VALUES (?, ?, ?)');
2853-
2854-
foreach my $transition (@workflow) {
2855-
my ($from, $to);
2856-
# If it's an initial state, there is no "old" value.
2857-
$from = $dbh->selectrow_array($sth_select, undef, $transition->[0])
2858-
if $transition->[0];
2859-
$to = $dbh->selectrow_array($sth_select, undef, $transition->[1]);
2860-
# If one of the bug statuses doesn't exist, the transition is invalid.
2861-
next if (($transition->[0] && !$from) || !$to);
2862-
2863-
$sth->execute($from, $to, $transition->[2] ? 1 : 0);
2822+
2823+
if (!$count) {
2824+
# Make sure the variables below are defined as
2825+
# status_workflow.require_comment cannot be NULL.
2826+
my $create = $old_params->{'commentoncreate'} || 0;
2827+
my $confirm = $old_params->{'commentonconfirm'} || 0;
2828+
my $accept = $old_params->{'commentonaccept'} || 0;
2829+
my $resolve = $old_params->{'commentonresolve'} || 0;
2830+
my $verify = $old_params->{'commentonverify'} || 0;
2831+
my $close = $old_params->{'commentonclose'} || 0;
2832+
my $reopen = $old_params->{'commentonreopen'} || 0;
2833+
# This was till recently the only way to get back to NEW for
2834+
# confirmed bugs, so we use this parameter here.
2835+
my $reassign = $old_params->{'commentonreassign'} || 0;
2836+
2837+
# This is the default workflow.
2838+
my @workflow = ([undef, 'UNCONFIRMED', $create],
2839+
[undef, 'NEW', $create],
2840+
[undef, 'ASSIGNED', $create],
2841+
['UNCONFIRMED', 'NEW', $confirm],
2842+
['UNCONFIRMED', 'ASSIGNED', $accept],
2843+
['UNCONFIRMED', 'RESOLVED', $resolve],
2844+
['NEW', 'ASSIGNED', $accept],
2845+
['NEW', 'RESOLVED', $resolve],
2846+
['ASSIGNED', 'NEW', $reassign],
2847+
['ASSIGNED', 'RESOLVED', $resolve],
2848+
['REOPENED', 'NEW', $reassign],
2849+
['REOPENED', 'ASSIGNED', $accept],
2850+
['REOPENED', 'RESOLVED', $resolve],
2851+
['RESOLVED', 'UNCONFIRMED', $reopen],
2852+
['RESOLVED', 'REOPENED', $reopen],
2853+
['RESOLVED', 'VERIFIED', $verify],
2854+
['RESOLVED', 'CLOSED', $close],
2855+
['VERIFIED', 'UNCONFIRMED', $reopen],
2856+
['VERIFIED', 'REOPENED', $reopen],
2857+
['VERIFIED', 'CLOSED', $close],
2858+
['CLOSED', 'UNCONFIRMED', $reopen],
2859+
['CLOSED', 'REOPENED', $reopen]);
2860+
2861+
print "Now filling the 'status_workflow' table with valid bug status transitions...\n";
2862+
my $sth_select = $dbh->prepare('SELECT id FROM bug_status WHERE value = ?');
2863+
my $sth = $dbh->prepare('INSERT INTO status_workflow (old_status, new_status,
2864+
require_comment) VALUES (?, ?, ?)');
2865+
2866+
foreach my $transition (@workflow) {
2867+
my ($from, $to);
2868+
# If it's an initial state, there is no "old" value.
2869+
$from = $dbh->selectrow_array($sth_select, undef, $transition->[0])
2870+
if $transition->[0];
2871+
$to = $dbh->selectrow_array($sth_select, undef, $transition->[1]);
2872+
# If one of the bug statuses doesn't exist, the transition is invalid.
2873+
next if (($transition->[0] && !$from) || !$to);
2874+
2875+
$sth->execute($from, $to, $transition->[2] ? 1 : 0);
2876+
}
28642877
}
2878+
2879+
# Make sure the bug status used by the 'duplicate_or_move_bug_status'
2880+
# parameter has all the required transitions set.
2881+
Bugzilla::Status::add_missing_bug_status_transitions();
28652882
}
28662883

28672884
1;

‎Bugzilla/Status.pm‎

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,22 @@ sub is_open { return $_[0]->{'is_open'}; }
5454
##### Methods ####
5555
###############################
5656

57+
sub closed_bug_statuses {
58+
my @bug_statuses = Bugzilla::Status->get_all;
59+
@bug_statuses = grep { !$_->is_open } @bug_statuses;
60+
return @bug_statuses;
61+
}
62+
5763
sub can_change_to {
5864
my $self = shift;
5965
my $dbh = Bugzilla->dbh;
6066

6167
if (!ref($self) || !defined $self->{'can_change_to'}) {
62-
my ($cond, @args);
68+
my ($cond, @args, $self_exists);
6369
if (ref($self)) {
6470
$cond = '= ?';
6571
push(@args, $self->id);
72+
$self_exists = 1;
6673
}
6774
else {
6875
$cond = 'IS NULL';
@@ -78,12 +85,37 @@ sub can_change_to {
7885
AND old_status $cond",
7986
undef, @args);
8087

88+
# Allow the bug status to remain unchanged.
89+
push(@$new_status_ids, $self->id) if $self_exists;
8190
$self->{'can_change_to'} = Bugzilla::Status->new_from_list($new_status_ids);
8291
}
8392

8493
return $self->{'can_change_to'};
8594
}
8695

96+
sub add_missing_bug_status_transitions {
97+
my $bug_status = shift || Bugzilla->params->{'duplicate_or_move_bug_status'};
98+
my $dbh = Bugzilla->dbh;
99+
my $new_status = new Bugzilla::Status({name => $bug_status});
100+
# Silently discard invalid bug statuses.
101+
$new_status || return;
102+
103+
my $missing_statuses = $dbh->selectcol_arrayref('SELECT id
104+
FROM bug_status
105+
LEFT JOIN status_workflow
106+
ON old_status = id
107+
AND new_status = ?
108+
WHERE old_status IS NULL',
109+
undef, $new_status->id);
110+
111+
my $sth = $dbh->prepare('INSERT INTO status_workflow
112+
(old_status, new_status) VALUES (?, ?)');
113+
114+
foreach my $old_status_id (@$missing_statuses) {
115+
next if ($old_status_id == $new_status->id);
116+
$sth->execute($old_status_id, $new_status->id);
117+
}
118+
}
87119

88120
1;
89121

@@ -100,6 +132,10 @@ Bugzilla::Status - Bug status class.
100132
my $bug_status = new Bugzilla::Status({name => 'ASSIGNED'});
101133
my $bug_status = new Bugzilla::Status(4);
102134
135+
my @closed_bug_statuses = Bugzilla::Status::closed_bug_statuses();
136+
137+
Bugzilla::Status::add_missing_bug_status_transitions($bug_status);
138+
103139
=head1 DESCRIPTION
104140
105141
Status.pm represents a bug status object. It is an implementation
@@ -113,6 +149,15 @@ below.
113149
114150
=over
115151
152+
=item C<closed_bug_statuses>
153+
154+
Description: Returns a list of C<Bugzilla::Status> objects which can have
155+
a resolution associated with them ("closed" bug statuses).
156+
157+
Params: none.
158+
159+
Returns: A list of Bugzilla::Status objects.
160+
116161
=item C<can_change_to>
117162
118163
Description: Returns the list of active statuses a bug can be changed to
@@ -122,6 +167,14 @@ below.
122167
123168
Returns: A list of Bugzilla::Status objects.
124169
170+
=item C<add_missing_bug_status_transitions>
171+
172+
Description: Insert all missing transitions to a given bug status.
173+
174+
Params: $bug_status - The value (name) of a bug status.
175+
176+
Returns: nothing.
177+
125178
=back
126179
127180
=cut

‎editparams.cgi‎

Lines changed: 4 additions & 0 deletions

0 commit comments

Comments
 (0)