"Date: " . htmlsanit($creationdate),
"Last Update: " . htmlsanit($lastchangedate),
"Severity: " . htmlsanit( $bug->{severity} ),
+ "Affects: " . htmlsanit(join(", ", $bug->tags("affects") ) ),
"State: " . b( $bug->{open} ? "Open" : "Closed" )
]
)
print header;
+my $jscript = <<'EOS';
+function showOldVersions() {
+ $( 'input.old_version[type=checkbox]' ).parents('td').show();
+ $( '#showOldVersions' ).hide();
+}
+
+$(document).ready(function() {
+ var showOld = false;
+ $( 'input.old_version[type=checkbox]' ).each(function() {
+ if ( $(this).is(':checked') ) { showOld = true; }
+ })
+
+ if ( showOld ) {
+ showOldVersions();
+ } else {
+ $( 'input.old_version[type=checkbox]' ).parents('td').hide();
+ }
+})
+EOS
+
print start_html(
-title => $c{TrackerName} . ": $ml - All Bugs",
- -style => { 'src' => $c{StyleSheet} }
+ -style => { 'src' => $c{StyleSheet} },
+ -script => [
+ { -type => 'text/javascript',
+ -src => '/javascript/jquery/jquery.js',
+ },
+ { -code => $jscript,
+ },
+ ]
+
) . "\n";
print h1( $c{TrackerName} );
$dbh,
State => param('state'),
Severities => [ param('severityfilter') ],
+ Affects => [ param('affectsfilter') ],
);
foreach my $open ( 1, 0 ) {
foreach my $sev ( @{ $c{SeverityLevels} } ) { buglist( $open, $sev ); }
}
-print ul (@index) if @index;
+if ( param('affectsfilter') ) {
+ print h2("Bugs affecting: " . join(", ",@{[param('affectsfilter')]}));
+} else {
+ print h2("Bugs affecting: any version");
+}
+print p(ul (@index)) if @index;
if ( !$lists ) {
$lists = h1("No bugs match the criteria.");
print h2("Search");
+sub affects_checkboxes() {
+ my @affects = list_tags($dbh, "affects");
+ my (@values, @defaults, %attributes);
+
+ foreach my $vers (@affects) {
+ push @values, $vers->{name};
+ push @defaults, $vers->{name} if $vers->{active} eq "true";
+ $attributes{$vers->{name}} = {};
+
+ $attributes{$vers->{name}}{'class'} = 'old_version' if $vers->{advanced} eq "true"
+ }
+ return checkbox_group(-name => 'affectsfilter',
+ -values => \@values,
+ -default => \@defaults,
+ -attributes => \%attributes);
+}
+
print
start_form( -method => "POST" ),
table(
]
),
td( [ "Title contains:", i("TBD") ] ), #textfield('titlefilter') ] ),
+ td( [ "Only Those Affecting:",
+ affects_checkboxes(),
+ small(a({-href=>"javascript:showOldVersions();", -id=>"showOldVersions"},"Show Older Versions"))
+ ]
+ ),
td(
[
"Severities:",
- join(
- "",
- checkbox_group(
- -name => 'severityfilter',
- -values => $c{SeverityLevels}
- )
+ checkbox_group(
+ -name => 'severityfilter',
+ -values => $c{SeverityLevels}
)
]
),
use Emesinae::Message;
use Emesinae::Common;
-my $SELECT_FIELDS = "bug_id,title_raw,creationdate,lastchangedate,owner_raw,severity,open";
+my $SELECT_FIELDS = "bugs.bug_id,title_raw,creationdate,lastchangedate,owner_raw,severity,open";
sub new {
my $class = shift;
$self->_set("severity", $sev);
}
+sub _lookup_tag($$$) {
+ my ($self,$ns,$tag) = @_;
+
+ my $sth = $self->{dbh}->prepare( "
+ SELECT tag_id
+ FROM tags
+ WHERE namespace = ?
+ AND name = ?
+ " );
+ $sth->execute ( $ns, $tag ) or die "Unable to find tag $ns:$tag";
+ my $row = $sth->fetchrow_arrayref;
+ $row or die "Unable to find tag $ns:$tag";
+ $sth->finish;
+
+ return $row->[0];
+}
+
+sub set_tag($$$) {
+ my ($self,$ns,$tag) = @_;
+
+ my $tag_id = $self->_lookup_tag($ns,$tag);
+
+ my $sth = $self->{dbh}->prepare( "
+ INSERT OR REPLACE INTO bug2tag(bug_id,tag_id)
+ VALUES (?,?)
+ " );
+ $sth->execute( $self->{id}, $tag_id ) or die "Setting tag $ns:$tag on Bug #" . $self->{id};
+ $sth->rows == 1 or die "Failed to set tag $ns:$tag on Bug #" . $self->{id};
+
+ $sth->finish;
+}
+
+sub clear_tag($$$) {
+ my ($self,$ns,$tag) = @_;
+
+ my $tag_id = $self->_lookup_tag($ns,$tag);
+
+ my $sth = $self->{dbh}->prepare( "
+ DELETE FROM bug2tag
+ WHERE bug_id = ?
+ AND tag_id = ?
+ " );
+ $sth->execute( $self->{id}, $tag_id ) or die "Clearing tag $ns:$tag on Bug #" . $self->{id};
+
+ $sth->finish;
+}
+
+sub tags($$) {
+ my ($self,$ns) = @_;
+
+ my $sth = $self->{dbh}->prepare( "
+ SELECT tags.name
+ FROM tags,bug2tag
+ WHERE tags.tag_id == bug2tag.tag_id
+ AND tags.namespace == ?
+ AND bug2tag.bug_id == ?
+ ");
+ $sth->execute( $ns, $self->{id} ) or die "Listing $ns tags on Bug #" . $self->{id};
+
+ # An array ref (rows) of array refs (columns)
+ my $tref = $sth->fetchall_arrayref();
+ $sth->finish;
+ return map { $_->[0] } @{$tref};
+}
+
sub set_status {
my $self = shift;
my $open = shift;
my $dbh = shift;
my %args = @_;
- my @where;
+ my (@args,@where);
+
+ my $select = "SELECT DISTINCT $SELECT_FIELDS FROM bugs";
if ( $args{State} eq "Open" ) { push @where, qq(open = "true" ) }
elsif ( $args{State} eq "Closed" ) { push @where, qq(open = "false" ) }
- if ( $args{Severities} ) {
+ if ( @{$args{Severities}} ) {
+ #print "<p>SEVERITIES: ".@{$args{Severities}}." ".join(" ",@{$args{Severities}})."</p>";
map { assert_valid_severity($_) } @ { $args{Severities} };
push @where,
- join( " OR ", map { qq{severity = "$_"} } @{ $args{Severities} } );
+ join( " OR ", map { push @args,$_; qq{severity = ?} } @{ $args{Severities} } );
+ }
+
+ if ( @{$args{Affects}} ) {
+ #print "<p>AFFECTS: ".@{$args{Affects}}." ".join(" ",@{$args{Affects}})."</p>";
+ $select .= " JOIN bug2tag ON bug2tag.bug_id == bugs.bug_id ";
+ $select .= " JOIN tags ON bug2tag.tag_id == tags.tag_id ";
+
+ push @where, "tags.namespace = \"affects\"";
+ push @where,
+ join( " OR ", map { push @args,$_; qq{tags.name = ?} } @{ $args{Affects} });
}
- my $select = "SELECT $SELECT_FIELDS FROM bugs ";
- $select .= "WHERE " . join( " AND ", map { qq{($_)} } @where ) if @where;
- $select .= " ORDER BY bug_id";
- #print "<p>$select</p>";
+ $select .= " WHERE " . join( " AND ", map { qq{($_)} } @where ) if @where;
+ $select .= " ORDER BY bugs.bug_id";
+
+ #print "<p>QUERY: $select</p>";
+ #print "<p>ARGS:".join(",", @args)."</p>";
+
my $sth = $dbh->prepare($select);
- $sth->execute();
+ $sth->execute(@args);
my @r;
while ( my @row = $sth->fetchrow_array ) {
push @r, $class->new( $dbh, Fields => \@row );
%c readconfig
opendb
listbugs
+ list_tags
subsyslock subsysunlock
);
%EXPORT_TAGS = ();
return $dbh;
}
+sub list_tags($$) {
+ my ($dbh,$ns) = @_;
+
+ my $sth = $dbh->prepare( "
+ SELECT name,active,advanced
+ FROM tags
+ WHERE namespace = ?
+ " );
+ $sth->execute( $ns ) or die "Unable to obtain list of tags in namesapce $ns";
+
+ # Gets an array ref of hash refs.
+ my $tags = $sth->fetchall_arrayref({});
+
+ $sth->finish;
+ return @{$tags}
+}
+
#------- locking -------
sub subsyslock ($) {
libdbd-sqlite3-perl
liburi-perl
+ libjs-jquery
+
sqlite3
MTA (currently only exim)
bugs:
- components
- - affected branches
- - tags
bug.pl:
- offer link to followup to a bug, but not reply to a specific message.
--- /dev/null
+From: Ian Campbell <IJC@heLlion.org.uk>
+Subject: Bug affects master and 4.2
+Message-id: <control.14.test@emesinae.example.com>
+To: emesinae-test@list.example.com
+Cc: ijc@hellion.org.uk, test-control@bugs.xenproject.org
+
+create !
+affects it master
+# A second time for good measure
+affects it +master
+affects it stable-4.2
+# Add and remove a tag
+affects it +stable-4.1
+affects it -stable-4.1
+# Remove a non-present tag
+affects it -stable-4.0
+thanks
--- /dev/null
+From: Ian Campbell <IJC@heLlion.org.uk>
+Subject: Bug affects unknown branch
+Message-id: <control.15.test@emesinae.example.com>
+To: emesinae-test@list.example.com
+Cc: ijc@hellion.org.uk, test-control@bugs.xenproject.org
+
+create !
+affects it foo
+thanks
--- /dev/null
+INSERT INTO tags (namespace,name,active,advanced) VALUES ("affects","master","true","false");
+INSERT INTO tags (namespace,name,active,advanced) VALUES ("affects","stable-4.2","true","false");
+INSERT INTO tags (namespace,name,active,advanced) VALUES ("affects","stable-4.1","false","true");
+INSERT INTO tags (namespace,name,active,advanced) VALUES ("affects","stable-4.0","false","true");
+
sudo ../../../db/createdb.sh -d $db
sudo chown $user:$user $db
+ sudo sqlite3 $db < ../../../config/examples/test/dbinit.sql
echo Inserting corpus
asuser ./insertcorpus.sh
--- /dev/null
+INSERT INTO tags (namespace,name,active,advanced) VALUES ("affects","master","true","false");
+INSERT INTO tags (namespace,name,active,advanced) VALUES ("affects","4.2","true","false");
+INSERT INTO tags (namespace,name,active,advanced) VALUES ("affects","4.1","false","true");
+INSERT INTO tags (namespace,name,active,advanced) VALUES ("affects","4.0","false","true");
+
Available Commands
==================
+affects <BUG> [+-]<VERSION> (, [+-]<VERSION>)?
+
+ Marks <BUG> as affecting one or more given <VERSIONS> or removes the
+ mark.
+
create <MSGID>
[MAINTONLY] Create a new bug, rooted at <MSGID>. By default the title
primary key ( parent_id, child_id )
);
---create table components {
--- id integer primary key autoincrement,
--- name varchar,
---}
---insert into components (name) VALUES "hypervisor";
---insert into components (name) VALUES "tools/libxc";
---insert into components (name) VALUES "tools/libxl";
---insert into components (name) VALUES "tools/qemu-xen";
---insert into components (name) VALUES "tools/qemu-xen-traditional";
---insert into components (name) VALUES "tools/misc";
---insert into components (name) VALUES "kernel/linux";
+create table tags (
+ tag_id integer not null primary key autoincrement,
+ namespace varchar, -- "component", "affects" etc
+ name varchar,
+ -- the following refer to the default visibility and setting in the search page.
+ active bool default true, -- searched for by default
+ advanced bool default false -- only shown in advanced search pane
+);
create table bugs (
bug_id integer primary key autoincrement,
bug_id integer not null references bugs ( bug_id ),
message_id integer not null references messages ( message_id )
);
+
+create table bug2tag (
+ bug_id integer not null references bugs ( bug_id ),
+ tag_id integer not null references tags ( tag_id ),
+ primary key ( bug_id, tag_id )
+);
return 1;
}
+sub cmd_affects ($) {
+ $_ = shift;
+ m/^(${MATCH_BUGID})\s+([\+-]?)(.*)/ or die "Cannot parse arguments";
+ my $b = lookup_bugid $1;
+ if ( $2 eq "+" or $2 eq "" ) {
+ push @reply, "Bug #" . $b->{id} . " affects `$3'";
+ $b->set_tag( "affects", $3 );
+ } else {
+ push @reply, "Bug #" . $b->{id} . " does not affect `$3'";
+ $b->clear_tag( "affects", $3 );
+ }
+}
+
sub cmd_prune ($) {
$_ = shift;
m/^($MATCH_BUGID)\s(.*)/ or die "Cannot parse arguments";
title => { Priv => 1, Cmd => \&cmd_title, },
owner => { Priv => 1, Cmd => \&cmd_owner, },
severity => { Priv => 1, Cmd => \&cmd_severity, },
+ affects => { Priv => 0, Cmd => \&cmd_affects, },
prune => { Priv => 0, Cmd => \&cmd_prune, },
graft => { Priv => 0, Cmd => \&cmd_graft, },
thanks => { Priv => 0, Cmd => \&cmd_quit, },