]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 661476: sanitycheck.pl should check if all products have components defined.
authorFrédéric Buclin <LpSolit@gmail.com>
Wed, 17 Aug 2011 11:05:31 +0000 (13:05 +0200)
committerFrédéric Buclin <LpSolit@gmail.com>
Wed, 17 Aug 2011 11:05:31 +0000 (13:05 +0200)
Also, creating a new product from the web UI asks you to create a component too.
r=glob a=LpSolit

Bugzilla/Component.pm
Bugzilla/Version.pm
editproducts.cgi
sanitycheck.cgi
template/en/default/admin/components/edit-common.html.tmpl
template/en/default/admin/products/create.html.tmpl
template/en/default/admin/products/edit-common.html.tmpl
template/en/default/admin/sanitycheck/messages.html.tmpl
template/en/default/global/messages.html.tmpl
template/en/default/global/user-error.html.tmpl

index 215119715d0f4817b6254c47052376b3b5824020..ceca7e7942b627fc6f2e717cd15cca16266db1e9 100644 (file)
@@ -155,6 +155,11 @@ sub remove_from_db {
 
     $dbh->bz_start_transaction();
 
+    # Products must have at least one component.
+    if (scalar(@{$self->product->components}) == 1) {
+        ThrowUserError('component_is_last', { comp => $self });
+    }
+
     if ($self->bug_count) {
         if (Bugzilla->params->{'allowbugdeletion'}) {
             require Bugzilla::Bug;
index 7f53add138996e95094a0deb847f9259bd5d5fa1..250c474cad2a1f2488d91d31dab2ded35534ed9a 100644 (file)
@@ -143,12 +143,21 @@ sub remove_from_db {
     my $self = shift;
     my $dbh = Bugzilla->dbh;
 
+    $dbh->bz_start_transaction();
+
+    # Products must have at least one version.
+    if (scalar(@{$self->product->versions}) == 1) {
+        ThrowUserError('version_is_last', { version => $self });
+    }
+
     # The version cannot be removed if there are bugs
     # associated with it.
     if ($self->bug_count) {
         ThrowUserError("version_has_bugs", { nb => $self->bug_count });
     }
     $self->SUPER::remove_from_db();
+
+    $dbh->bz_commit_transaction();
 }
 
 ###############################
index 6d5c5e59356287ee9ca0f9d40147822e61801773..ed6596130103fc8c7eb71fc9d4c8354681d5f4e3 100755 (executable)
@@ -37,6 +37,7 @@ use Bugzilla::Util;
 use Bugzilla::Error;
 use Bugzilla::Group;
 use Bugzilla::Product;
+use Bugzilla::Component;
 use Bugzilla::Classification;
 use Bugzilla::Token;
 
@@ -176,7 +177,13 @@ if ($action eq 'new') {
 
     check_token_data($token, 'add_product');
 
-    my %create_params = (
+    Bugzilla::User::match_field ({
+        'initialowner'     => { 'type' => 'single' },
+        'initialqacontact' => { 'type' => 'single' },
+        'initialcc'        => { 'type' => 'multi'  },
+    });
+
+    my %product_create_params = (
         classification   => $classification_name,
         name             => $product_name,
         description      => scalar $cgi->param('description'),
@@ -186,7 +193,23 @@ if ($action eq 'new') {
         create_series    => scalar $cgi->param('createseries'),
         allows_unconfirmed => scalar $cgi->param('allows_unconfirmed'),
     );
-    my $product = Bugzilla::Product->create(\%create_params);
+
+    $dbh->bz_start_transaction();
+    my $product = Bugzilla::Product->create(\%product_create_params);
+
+    my @initial_cc = $cgi->param('initialcc');
+    my %component_create_params = (
+        product          => $product,
+        name             => trim($cgi->param('component') || ''),
+        description      => scalar $cgi->param('comp_desc'),
+        initialowner     => scalar $cgi->param('initialowner'),
+        initialqacontact => scalar $cgi->param('initialqacontact'),
+        initial_cc       => \@initial_cc,
+        create_series    => scalar $cgi->param('createseries'),
+   );
+
+    Bugzilla::Component->create(\%component_create_params);
+    $dbh->bz_commit_transaction();
 
     delete_token($token);
 
index da308aaebb356ee3f8e61a3a5552a93c59ef662b..7b8177d8327305ce0d3b5ac5c54f9fa0926b37b1 100755 (executable)
@@ -747,6 +747,26 @@ if (scalar(@invalid_flags)) {
     }
 }
 
+###########################################################################
+# Check for products with no component
+###########################################################################
+
+Status('product_check_start');
+
+my $products_missing_data = $dbh->selectcol_arrayref(
+      'SELECT DISTINCT products.name
+         FROM products
+    LEFT JOIN components
+           ON components.product_id = products.id
+    LEFT JOIN versions
+           ON versions.product_id = products.id
+        WHERE components.id IS NULL
+           OR versions.id IS NULL');
+
+if (scalar(@$products_missing_data)) {
+    Status('product_alert', { name => $_ }, 'alert') foreach @$products_missing_data;
+}
+
 ###########################################################################
 # General bug checks
 ###########################################################################
index 069b56cfdc2b10bc14318ff7800ed77b5483a358..6f65095aff883957337dcc598cea4f9208925f58 100644 (file)
   # comp: object; Bugzilla::Component object.
   #%]
 
+[%# When called from the "New Product" page, the component description field
+  # must have a name different from the product description field. %]
+[% DEFAULT desc_name = "description" %]
+
 <tr>
-  <td valign="top">Component:</td>
+  <th align="right">Component:</th>
   <td><input size="64" maxlength="64" name="component"
              value="[%- comp.name FILTER html %]"></td>
 </tr>
 <tr>
-  <td valign="top">Component Description:</td>
+  <th align="right">Component Description:</th>
   <td>
     [% INCLUDE global/textarea.html.tmpl
-      name           = 'description'
+      name           = desc_name
       minrows        = 4
       cols           = 64
       wrap           = 'virtual'
@@ -40,7 +44,7 @@
   </td>
 </tr>
 <tr>
-  <td valign="top"><label for="initialowner">Default Assignee:</label></td>
+  <th align="right"><label for="initialowner">Default Assignee:</label></th>
   <td>
     [% INCLUDE global/userselect.html.tmpl
        name => "initialowner"
@@ -52,7 +56,7 @@
 </tr>
 [% IF Param('useqacontact') %]
   <tr>
-    <td valign="top"><label for="initialqacontact">Default QA contact:</label></td>
+    <th align="right"><label for="initialqacontact">Default QA contact:</label></th>
     <td>
       [% INCLUDE global/userselect.html.tmpl
          name => "initialqacontact"
@@ -65,9 +69,7 @@
   </tr>
 [% END %]
 <tr>
-  <td valign="top">
-    <label for="initialcc">Default CC List:</label>
-  </td>
+  <th align="right"><label for="initialcc">Default CC List:</label></th>
   <td>
     [% INCLUDE global/userselect.html.tmpl
        name     => "initialcc"
index 3af81fb23d0388de60eb2edf2b61816a8fc5ca02..2b60645abef056294dbb5be7f28f6d27ec2216cb 100644 (file)
@@ -25,7 +25,8 @@
 [% PROCESS global/header.html.tmpl
   title = title
   style_urls = ['skins/standard/admin.css']
-  javascript_urls = ['js/util.js']
+  javascript_urls = ['js/util.js', 'js/field.js']
+  yui = [ 'autocomplete' ]
 %]
 
 [% DEFAULT
@@ -42,7 +43,7 @@
 
     <tr>
       <th align="right">Version:</th>
-      <td><input size="64" maxlength="255" name="version" 
+      <td><input size="20" maxlength="64" name="version" 
                 value="[% version FILTER html %]">
       </td>
     </tr>
         <input type="checkbox" name="createseries" value="1" checked="checked">
       </td>
     </tr>
+
+    <tr>
+      <td colspan="2">&nbsp;</td>
+    </tr>
+    <tr>
+      <td colspan="2">
+        This product must have at least one component.
+        You will be able to create additional components later:
+      </td>
+    </tr>
+
+    [% PROCESS "admin/components/edit-common.html.tmpl" desc_name = "comp_desc" %]
   </table>
 
   <input type="submit" id="add-product" value="Add">
index 4812707cdbd9c05cf23a97e0c153403ca1f6d262..eac33ea9aed773366fd21a021b562774b1a8183a 100644 (file)
@@ -25,7 +25,7 @@
 
 [% IF Param('useclassification') %]
   <tr>
-    <th align="right"><b>Classification:</b></th>
+    <th align="right">Classification:</th>
     <td><b>[% classification.name FILTER html %]</b></td>
   </tr>
 [% END %]
   </td>
 </tr>
 
+<tr>
+  <th align="right">Open for [% terms.bug %] entry:</th>
+  <td><input type="checkbox" name="is_active" value="1"
+       [% ' checked="checked"' IF product.is_active %]>
+  </td>
+</tr>
+<tr>
+  <th align="right">
+    <label for="allows_unconfirmed">Enable the
+      [%+ display_value('bug_status', 'UNCONFIRMED') FILTER html %] status
+      in this product:</label>
+  </th>
+  <td><input type="checkbox" id="allows_unconfirmed" name="allows_unconfirmed"
+             [% ' checked="checked"' IF product.allows_unconfirmed %]>
+  </td>
+</tr>
+
 [% IF Param('usetargetmilestone') -%]
   <tr>
     <th align="right">Default milestone:</th>
   </tr>
 [% END %]
     
-<tr>
-  <th align="right">Open for [% terms.bug %] entry:</th>
-  <td><input type="checkbox" name="is_active" value="1"
-       [% ' checked="checked"' IF product.is_active %]>
-  </td>
-</tr>
-<tr>
-  <th align="right">
-    <label for="allows_unconfirmed">Enable the
-      [%+ display_value('bug_status', 'UNCONFIRMED') FILTER html %] status
-      in this product:</label>
-  </th>
-  <td><input type="checkbox" id="allows_unconfirmed" name="allows_unconfirmed"
-             [% ' checked="checked"' IF product.allows_unconfirmed %]>
-  </td>
-</tr>
-
 [% Hook.process('rows') %]
index 88264d820f949e7944a7583518bd3d30e5f2f3b6..494a8cdf010a518a6dcef6e9ef4b80218ea34918 100644 (file)
   [% ELSIF san_tag == "profile_login_start" %]
     Checking profile logins.
 
+  [% ELSIF san_tag == "product_alert" %]
+    Product <a href="editproducts.cgi?product=[% name FILTER html%]">
+    [%- name FILTER html %]</a> has no components or no versions.
+
+  [% ELSIF san_tag == "product_check_start" %]
+    Checking products with no components or versions.
+
   [% ELSIF san_tag == "profile_login_alert" %]
     Bad profile email address, id=[% id FILTER html %],
     &lt;[% email FILTER html %]&gt;.
index 01eb3265153cbe70d4d5df53b513d6df484ccd0c..a57449d7c0000ebb7416e390b87e5611784f02a6 100644 (file)
 
   [% ELSIF message_tag == "product_created" %]
     [% title = "Product Created" %]
-    The product <em>[% product.name FILTER html %]</em> has been created. You will need to
-    <a href="editcomponents.cgi?action=add&product=[% product.name FILTER uri %]">
-    add at least one component</a> before anyone can enter [% terms.bugs %] against this product.
+    The product <em>[% product.name FILTER html %]</em> has been created.
 
   [% ELSIF message_tag == "product_deleted" %]
     [% title = "Product Deleted" %]
index 52c6156b6e080861c7692614a1e5c3563ebe2f0a..7dac2ee55cc52168be293ff720bf61b20bb5e0ed 100644 (file)
     You must reassign those [% terms.bugs %] to another component before you
     can delete this one.
 
+  [% ELSIF error == "component_is_last" %]
+    [% title = BLOCK %]Last Component in this Product[% END %]
+    '[% comp.name FILTER html %]' is the last component of the
+    '[% comp.product.name FILTER html %]' product. You cannot delete it.
+
   [% ELSIF error == "component_name_too_long" %]
     [% title = "Component Name Is Too Long" %]
     The name of a component is limited to [% constants.MAX_COMPONENT_SIZE FILTER html %]
     version! You must reassign those [% terms.bugs %] to another version
     before you can delete this one.
 
+  [% ELSIF error == "version_is_last" %]
+    [% title = BLOCK %]Last Version in this Product[% END %]
+    '[% version.name FILTER html %]' is the last version of the
+    '[% version.product.name FILTER html %]' product. You cannot delete it.
+
   [% ELSIF error == "users_deletion_disabled" %]
     [% title = "Deletion not activated" %]
     [% admindocslinks = {'useradmin.html' => 'User administration'} %]