diff options
author | David Lawrence <dlawrence@mozilla.com> | 2011-10-05 00:25:23 +0200 |
---|---|---|
committer | David Lawrence <dlawrence@mozilla.com> | 2011-10-05 00:25:23 +0200 |
commit | 57584dc4744fea59833ef355f7513690d246c70f (patch) | |
tree | 805f2b2941eca17eaf97263165d11d9e676ad9d1 /contrib | |
parent | 785580c6c290b93fe25868cfbb5d4e300749de62 (diff) | |
download | bugzilla-57584dc4744fea59833ef355f7513690d246c70f.tar.gz bugzilla-57584dc4744fea59833ef355f7513690d246c70f.tar.xz |
more porting work
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/addcustomfield.pl | 62 | ||||
-rw-r--r-- | contrib/fix_comment_text.pl | 75 | ||||
-rw-r--r-- | contrib/moco-ldap-check.pl | 224 | ||||
-rw-r--r-- | contrib/reorg-tools/README | 9 | ||||
-rw-r--r-- | contrib/reorg-tools/bmo-plan.txt | 82 | ||||
-rw-r--r-- | contrib/reorg-tools/fixgroupqueries.pl | 119 | ||||
-rw-r--r-- | contrib/reorg-tools/fixqueries.pl | 132 | ||||
-rw-r--r-- | contrib/reorg-tools/migrate_crash_signatures.pl | 126 | ||||
-rw-r--r-- | contrib/reorg-tools/move_flag_types.pl | 168 | ||||
-rw-r--r-- | contrib/reorg-tools/movebugs.pl | 151 | ||||
-rw-r--r-- | contrib/reorg-tools/movecomponent.pl | 193 | ||||
-rw-r--r-- | contrib/reorg-tools/syncflags.pl | 86 | ||||
-rw-r--r-- | contrib/reorg-tools/syncmsandversions.pl | 107 | ||||
-rw-r--r-- | contrib/sanitizeme.pl | 176 | ||||
-rw-r--r-- | contrib/verify-user.pl | 129 |
15 files changed, 1839 insertions, 0 deletions
diff --git a/contrib/addcustomfield.pl b/contrib/addcustomfield.pl new file mode 100644 index 000000000..c7f93c297 --- /dev/null +++ b/contrib/addcustomfield.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl -wT +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Frédéric Buclin <LpSolit@gmail.com> +# David Miller <justdave@mozilla.com> + +use strict; +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Field; + +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +my %types = ( + 'freetext' => FIELD_TYPE_FREETEXT, + 'single_select' => FIELD_TYPE_SINGLE_SELECT, + 'multi_select' => FIELD_TYPE_MULTI_SELECT, + 'textarea' => FIELD_TYPE_TEXTAREA, + 'datetime' => FIELD_TYPE_DATETIME, + 'bug_id' => FIELD_TYPE_BUG_ID, + 'bug_urls' => FIELD_TYPE_BUG_URLS, + 'keywords' => FIELD_TYPE_KEYWORDS, +); + +my $syntax = + "syntax: addcustomfield.pl <field name> [field type]\n\n" . + "valid field types:\n " . join("\n ", sort keys %types) . "\n\n" . + "the default field type is single_select\n"; + +my $name = shift || die $syntax; +my $type = lc(shift || 'single_select'); +exists $types{$type} || die "Invalid field type '$type'.\n\n$syntax"; +$type = $types{$type}; + +Bugzilla::Field->create({ + name => $name, + description => 'Please give me a description!', + type => $type, + mailhead => 0, + enter_bug => 0, + obsolete => 1, + custom => 1, + buglist => 1, +}); +print "Done!\n"; + +my $urlbase = Bugzilla->params->{urlbase}; +print "Please visit ${urlbase}editfields.cgi?action=edit&name=$name to finish setting up this field.\n"; diff --git a/contrib/fix_comment_text.pl b/contrib/fix_comment_text.pl new file mode 100644 index 000000000..f17bbc3d4 --- /dev/null +++ b/contrib/fix_comment_text.pl @@ -0,0 +1,75 @@ +#!/usr/bin/perl +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Initial Developer of the Original Code is Mozilla Foundation +# Portions created by the Initial Developer are Copyright (C) 2011 the +# Initial Developer. All Rights Reserved. +# +#=============================================================================== +# +# FILE: fix_comment_text.pl +# +# USAGE: ./fix_comment_text.pl <comment_id> +# +# DESCRIPTION: Updates a comment in Bugzilla with the text after __DATA__ +# +# OPTIONS: <comment_id> - The comment id from longdescs with the comment +# to be replaced. +# REQUIREMENTS: --- +# BUGS: --- +# NOTES: --- +# AUTHOR: David Lawrence (:dkl), dkl@mozilla.com +# COMPANY: Mozilla Foundation +# VERSION: 1.0 +# CREATED: 06/20/2011 03:40:22 PM +# REVISION: --- +#=============================================================================== + +use strict; +use warnings; + +use lib "."; + +use Bugzilla; +use Bugzilla::Util qw(detaint_natural); + +my $comment_id = shift; + +if (!detaint_natural($comment_id)) { + print "Error: invalid comment id or comment id not provided.\n" . + "Usage: ./fix_comment_text.pl <comment_id>\n"; + exit(1); +} + +my $dbh = Bugzilla->dbh; + +my $comment = join("", <DATA>); + +if ($comment =~ /ENTER NEW COMMENT TEXT HERE/) { + print "Please enter the new comment text in the script " . + "after the __DATA__ marker.\n"; + exit(1); +} + +$dbh->bz_start_transaction; + +Bugzilla->dbh->do( + "UPDATE longdescs SET thetext = ? WHERE comment_id = ?", + undef, $comment, $comment_id); + +$dbh->bz_commit_transaction; + +exit(0); + +__DATA__ +ENTER NEW COMMENT TEXT HERE BELOW THE __DATA__ MARKER! diff --git a/contrib/moco-ldap-check.pl b/contrib/moco-ldap-check.pl new file mode 100644 index 000000000..59f515bf2 --- /dev/null +++ b/contrib/moco-ldap-check.pl @@ -0,0 +1,224 @@ +#!/usr/bin/perl -wT +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is the Mozilla +# Foundation. Portions created by Mozilla are +# Copyright (C) 2011 Mozilla Foundation. All Rights Reserved. +# +# Contributor(s): Byron Jones <glob@mozilla.com> + +use strict; + +use lib qw(.); + +use Net::LDAP; +use XMLRPC::Lite; +use HTTP::Cookies; +use LWP::UserAgent; +use Term::ReadKey; +$| = 1; + +# +# +# + +print STDERR <<EOF; +This script cross-checks members of the Bugzilla mozilla-corporation group +with Mozilla's LDAP repository. + +To run this script you need: + - a bugzilla.mozilla.org admin account + - a Mozilla LDAP account + +EOF + +my $bugzillaLogin = get_text('bl', 'Bugzilla Login: '); +my $bugzillaPassword = get_text('bp', 'Bugzilla Password: ', 1); +my $ldapLogin = get_text('ll', 'LDAP Login: '); +my $ldapPassword = get_text('lp', 'LDAP Password: ', 1); + +sub get_text { + my($switch, $prompt, $password) = @_; + + for (my $i = 0; $i <= $#ARGV; $i++) { + if ($ARGV[$i] eq "-$switch") { + return $ARGV[$i + 1]; + } + } + + print STDERR $prompt; + my $response = ''; + ReadMode 4; + my $ch; + while(1) { + 1 while (not defined ($ch = ReadKey(-1))); + exit if $ch eq "\3"; + last if $ch =~ /[\r\n]/; + if ($ch =~ /[\b\x7F]/) { + next if $response eq ''; + chop $response; + print "\b \b"; + next; + } + if ($ch eq "\025") { + my $len = length($response); + print(("\b" x $len) . (" " x $len) . ("\b" x $len)); + $response = ''; + next; + } + next if ord($ch) < 32; + $response .= $ch; + print STDERR $password ? '*' : $ch; + } + ReadMode 0; + print STDERR "\n"; + return $response; +} +END { + ReadMode 0; +} + +# +# get list of users in mo-co group +# + +my %bugzilla; +{ + my $cookie_jar = HTTP::Cookies->new(file => "cookies.txt", autosave => 1); + my $proxy = XMLRPC::Lite->proxy( + 'https://bugzilla.mozilla.org/xmlrpc.cgi', + 'cookie_jar' => $cookie_jar); + my $response; + + print STDERR "Logging in to Bugzilla...\n"; + $response = $proxy->call( + 'User.login', + { + login => $bugzillaLogin, + password => $bugzillaPassword, + remember => 1, + } + ); + if ($response->fault) { + my ($package, $filename, $line) = caller; + die $response->faultstring . "\n"; + } + + my $ua = LWP::UserAgent->new(); + $ua->cookie_jar($cookie_jar); + $response = $ua->get('https://bugzilla.mozilla.org/editusers.cgi?' . + 'action=list&matchvalue=login_name&matchstr=&matchtype=substr&' . + 'grouprestrict=1&groupid=42'); + if (!$response->is_success) { + die $response->status_line; + } + + print STDERR "Getting user list from Bugzilla...\n"; + my $content = $response->content; + while ( + $content =~ m# + <td([^>]*)>[^<]+ + <a\shref="editusers[^"]+">([^<]+)</a>[^<]+ + </td>[^<]+ + <td[^>]*>([^<]+)</td> + #gx + ) { + my ($class, $email, $name) = ($1, $2, $3); + next if $class =~ /bz_inactive/; + $email =~ s/(^\s+|\s+$)//g; + $email =~ s/@/@/; + next unless $email =~ /@/; + $name =~ s/(^\s+|\s+$)//g; + $bugzilla{lc $email} = $name; + } +} + +# +# build list of current mo-co bugmail accounts +# + +my %ldap; +{ + print STDERR "Logging into LDAP...\n"; + my $ldap = Net::LDAP->new('addressbook.mozilla.com', + scheme => 'ldaps', onerror => 'die') or die "$@"; + $ldap->bind("mail=$ldapLogin,o=com,dc=mozilla", password => $ldapPassword); + my $result = $ldap->search( + base => 'o=com,dc=mozilla', + scope => 'sub', + filter => '(mail=*)', + attrs => ['mail', 'bugzillaEmail', 'emailAlias', 'cn', 'employeeType'], + ); + print STDERR "Getting user list from LDAP...\n"; + foreach my $entry ($result->entries) { + my ($name, $bugMail, $mail, $type) = + map { $entry->get_value($_) || '' } + qw(cn bugzillaEmail mail employeeType); + next if $type eq 'DISABLED'; + $mail = lc $mail; + $ldap{$mail}{name} = $name; + $ldap{$mail}{bugMail} = lc $bugMail; + $ldap{$mail}{alias} = {}; + foreach my $alias ( + @{$entry->get_value('emailAlias', asref => 1) || []} + ) { + $ldap{$mail}{alias}{lc $alias} = 1; + } + } +} + +# +# cross-check +# + +my @invalid; +foreach my $bugzilla (sort keys %bugzilla) { + # check for matching bugmail entry + my $exists = 0; + foreach my $mail (sort keys %ldap) { + next unless $ldap{$mail}{bugMail} eq $bugzilla; + $exists = 1; + last; + } + next if $exists; + + # check for matching mail + $exists = 0; + foreach my $mail (sort keys %ldap) { + next unless $mail eq $bugzilla; + $exists = 1; + last; + } + next if $exists; + + # check for matching email alias + $exists = 0; + foreach my $mail (sort keys %ldap) { + next unless exists $ldap{$mail}{alias}{$bugzilla}; + $exists = 1; + last; + } + next if $exists; + + push @invalid, $bugzilla; +} + +my $max_length = 0; +foreach my $email (@invalid) { + $max_length = length($email) if length($email) > $max_length; +} +foreach my $email (@invalid) { + printf "%-${max_length}s %s\n", $email, $bugzilla{$email}; +} diff --git a/contrib/reorg-tools/README b/contrib/reorg-tools/README new file mode 100644 index 000000000..4e5d6eb4d --- /dev/null +++ b/contrib/reorg-tools/README @@ -0,0 +1,9 @@ +Upstreaming attempt: https://bugzilla.mozilla.org/show_bug.cgi?id=616499 + +Included in this directory is a group of tools we've used for moving components +around in a Bugzilla 3.2 install on bugzilla.mozilla.org. + +They may require tweaking if you use them on your own install. Putting them +here to make it easier to collaborate on them and keep them up-to-date. +Hopefully Bugzilla upstream will be able to just do this from the web UI +eventually. diff --git a/contrib/reorg-tools/bmo-plan.txt b/contrib/reorg-tools/bmo-plan.txt new file mode 100644 index 000000000..838ff0ab9 --- /dev/null +++ b/contrib/reorg-tools/bmo-plan.txt @@ -0,0 +1,82 @@ +==BMO Reorg Plan== + +Do the following things, mostly in order (but see "Timing" at the end): + +1) Create new classifications using GUI: + Graveyard (Description: "Old, retired products", sort key: <last>) + +2) Rename classifications using GUI: + Client Support to Other + +3) Move products between classification using GUI: + Grendel from Client Software to Graveyard + CCK from Unclassified to Graveyard + Derivatives from Unclassified to Graveyard + MozillaClassic from Unclassified to Graveyard + UI: "reclassify" link from the top-level classification list + +4) Create new products using GUI: + Core Graveyard in Graveyard + (desc: "Old, retired Core components", closed for entry, no charts) + MailNews Core in Components + (desc: "Mail and news components common to Thunderbird and SeaMonkey", + open for bug entry, create charts) + +5) Rename products using GUI, and fix queries using fixqueries.pl: +mysql> update series_categories set name="SeaMonkey (2)" where id=32; + Mozilla Application Suite to SeaMonkey + Sumo to support.mozilla.com + +5.5) Rename versions and milestones in Toolkit to match Firefox before step 6 + +6) Sync milestones, versions and groups between products using +syncmsandversions.pl: + Core -> Core Graveyard (new) + Core -> MailNews Core (new) + Firefox -> Toolkit + Core -> SeaMonkey + mozilla.org -> Websites (only 1) + +6.5) Sync flag inclusions using syncflags.pl: + Core -> Core Graveyard (new) + Core -> MailNews Core (new) + Core -> SeaMonkey + mozilla.org -> Websites (only 1) + +6.7) Allow Firefox flags temporarily in Toolkit: + 250 | blocking-firefox3 | blocking1.9 - 387 + 419 | blocking-firefox3.1 | blocking1.9.1 - 416 + 63 | blocking0.8 | blocking1.6 - 69 + 76 | blocking0.9 | blocking1.7 - 83 + 36 | review | review - 4 + 356 | wanted-firefox3 | wanted1.9 - 357 + 418 | wanted-firefox3.1 | wanted1.9.1 - 417 + +7) Move components using movecomponent.pl. + Any instruction beginning "moved from". + Can't fix the queries for this - oh well + <Very long list> + +8) Rename components using GUI, and fix queries using fixqueries.pl. + Any instruction beginning "renamed from" or "MailNews: prefix removed". + <Long list> + +9) Create new components using GUI. + Any instruction beginning "new". + <Long list> + +10) Move open bugs using GUI: + XP Miscellany to Core/General + +11) Merge components by moving bugs using GUI: + Any instruction beginning "merge in". + Merge all bugs, including closed. Delete empty component when done. + <long list of merges> + +12) Close Core Graveyard (and Grendel if necessary) to new bugs + +13) Rename Toolkit versions and milestones back (from 5.5) + +14) Execute flag mapping SQL using Reed's mapping to update bugs in Toolkit + +15) Disable above-listed flags in point 6.7 in Toolkit again diff --git a/contrib/reorg-tools/fixgroupqueries.pl b/contrib/reorg-tools/fixgroupqueries.pl new file mode 100644 index 000000000..1c75edb97 --- /dev/null +++ b/contrib/reorg-tools/fixgroupqueries.pl @@ -0,0 +1,119 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Gervase Markham <gerv@gerv.net> + +use strict; + +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Util; + +sub usage() { + print <<USAGE; +Usage: fixgroupqueries.pl <oldvalue> <newvalue> + +E.g.: fixgroupqueries.pl w-security webtools-security +will change all occurrences of "w-security" to "webtools-security" in the +appropriate places in the namedqueries. + +Note that all parameters are case-sensitive. +USAGE +} + +sub do_namedqueries($$) { + my ($old, $new) = @_; + $old = url_quote($old); + $new = url_quote($new); + + my $dbh = Bugzilla->dbh; + + my $replace_count = 0; + my $query = $dbh->selectall_arrayref("SELECT id, query FROM namedqueries"); + if ($query) { + my $sth = $dbh->prepare("UPDATE namedqueries SET query = ? + WHERE id = ?"); + + foreach my $row (@$query) { + my ($id, $query) = @$row; + if (($query =~ /field\d+-\d+-\d+=bug_group/) && + ($query =~ /(?:^|&|;)value\d+-\d+-\d+=$old(?:;|&|$)/)) { + $query =~ s/((?:^|&|;)value\d+-\d+-\d+=)$old(;|&|$)/$1$new$2/; + $sth->execute($query, $id); + $replace_count++; + } + } + } + + print "namedqueries: $replace_count replacements made.\n"; +} + +# series +sub do_series($$) { + my ($old, $new) = @_; + $old = url_quote($old); + $new = url_quote($new); + + my $dbh = Bugzilla->dbh; + #$dbh->bz_start_transaction(); + + my $replace_count = 0; + my $query = $dbh->selectall_arrayref("SELECT series_id, query + FROM series"); + if ($query) { + my $sth = $dbh->prepare("UPDATE series SET query = ? + WHERE series_id = ?"); + foreach my $row (@$query) { + my ($series_id, $query) = @$row; + + if (($query =~ /field\d+-\d+-\d+=bug_group/) && + ($query =~ /(?:^|&|;)value\d+-\d+-\d+=$old(?:;|&|$)/)) { + $query =~ s/((?:^|&|;)value\d+-\d+-\d+=)$old(;|&|$)/$1$new$2/; + $sth->execute($query, $series_id); + $replace_count++; + } + } + } + + #$dbh->bz_commit_transaction(); + print "series: $replace_count replacements made.\n"; +} + +############################################################################# +# MAIN CODE +############################################################################# +# This is a pure command line script. +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 2) { + usage(); + exit(); +} + +my ($old, $new) = @ARGV; + +print "Changing all instances of '$old' to '$new'.\n\n"; + +#do_namedqueries($old, $new); +do_series($old, $new); + +exit(0); diff --git a/contrib/reorg-tools/fixqueries.pl b/contrib/reorg-tools/fixqueries.pl new file mode 100644 index 000000000..4b862fd72 --- /dev/null +++ b/contrib/reorg-tools/fixqueries.pl @@ -0,0 +1,132 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Gervase Markham <gerv@gerv.net> + +use strict; + +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Util; + +sub usage() { + print <<USAGE; +Usage: fixqueries.pl <parameter> <oldvalue> <newvalue> + +E.g.: fixqueries.pl product FoodReplicator SeaMonkey +will change all occurrences of "FoodReplicator" to "Seamonkey" in the +appropriate places in the namedqueries, series and series_categories tables. + +Note that all parameters are case-sensitive. +USAGE +} + +sub do_namedqueries($$$) { + my ($field, $old, $new) = @_; + $old = url_quote($old); + $new = url_quote($new); + + my $dbh = Bugzilla->dbh; + #$dbh->bz_start_transaction(); + + my $replace_count = 0; + my $query = $dbh->selectall_arrayref("SELECT id, query FROM namedqueries"); + if ($query) { + my $sth = $dbh->prepare("UPDATE namedqueries SET query = ? + WHERE id = ?"); + + foreach my $row (@$query) { + my ($id, $query) = @$row; + if ($query =~ /(?:^|&|;)$field=$old(?:&|$|;)/) { + $query =~ s/((?:^|&|;)$field=)$old(;|&|$)/$1$new$2/; + $sth->execute($query, $id); + $replace_count++; + } + } + } + + #$dbh->bz_commit_transaction(); + print "namedqueries: $replace_count replacements made.\n"; +} + +# series +sub do_series($$$) { + my ($field, $old, $new) = @_; + $old = url_quote($old); + $new = url_quote($new); + + my $dbh = Bugzilla->dbh; + #$dbh->bz_start_transaction(); + + my $replace_count = 0; + my $query = $dbh->selectall_arrayref("SELECT series_id, query + FROM series"); + if ($query) { + my $sth = $dbh->prepare("UPDATE series SET query = ? + WHERE series_id = ?"); + foreach my $row (@$query) { + my ($series_id, $query) = @$row; + + if ($query =~ /(?:^|&|;)$field=$old(?:&|$|;)/) { + $query =~ s/((?:^|&|;)$field=)$old(;|&|$)/$1$new$2/; + $replace_count++; + } + + $sth->execute($query, $series_id); + } + } + + #$dbh->bz_commit_transaction(); + print "series: $replace_count replacements made.\n"; +} + +# series_categories +sub do_series_categories($$) { + my ($old, $new) = @_; + my $dbh = Bugzilla->dbh; + + $dbh->do("UPDATE series_categories SET name = ? WHERE name = ?", + undef, + ($new, $old)); +} + +############################################################################# +# MAIN CODE +############################################################################# +# This is a pure command line script. +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 3) { + usage(); + exit(); +} + +my ($field, $old, $new) = @ARGV; + +print "Changing all instances of '$old' to '$new'.\n\n"; + +do_namedqueries($field, $old, $new); +do_series($field, $old, $new); +do_series_categories($old, $new); + +exit(0); + diff --git a/contrib/reorg-tools/migrate_crash_signatures.pl b/contrib/reorg-tools/migrate_crash_signatures.pl new file mode 100644 index 000000000..b12446280 --- /dev/null +++ b/contrib/reorg-tools/migrate_crash_signatures.pl @@ -0,0 +1,126 @@ +#!/usr/bin/perl +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Initial Developer of the Original Code is Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2011 the +# Initial Developer. All Rights Reserved. +# +#=============================================================================== +# +# FILE: migrate_crash_signatures.pl +# +# USAGE: ./migrate_crash_signatures.pl +# +# DESCRIPTION: Migrate current summary data on matched bugs to the +# new cf_crash_signature custom fields. +# +# OPTIONS: No params, then performs dry-run without updating the database. +# If a true value is passed as single argument, then the database +# is updated. +# REQUIREMENTS: None +# BUGS: 577724 +# NOTES: None +# AUTHOR: David Lawrence (dkl@mozilla.com), +# COMPANY: Mozilla Corproation +# VERSION: 1.0 +# CREATED: 05/31/2011 03:57:52 PM +# REVISION: 1 +#=============================================================================== + +use strict; +use warnings; + +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Util; + +use Data::Dumper; + +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +my $UPDATE_DB = shift; # Pass true value as single argument to perform database update + +my $dbh = Bugzilla->dbh; + +# User to make changes as +my $user_id = $dbh->selectrow_array( + "SELECT userid FROM profiles WHERE login_name='nobody\@mozilla.org'"); +$user_id or die "Can't find user ID for 'nobody\@mozilla.org'\n"; + +my $field_id = $dbh->selectrow_array( + "SELECT id FROM fielddefs WHERE name = 'cf_crash_signature'"); +$field_id or die "Can't find field ID for 'cf_crash_signature' field\n"; + +# Search criteria +# a) crash or topcrash keyword, +# b) not have [notacrash] in whiteboard, +# c) have a properly formulated [@ ...] + +# crash and topcrash keyword ids +my $crash_keyword_id = $dbh->selectrow_array( + "SELECT id FROM keyworddefs WHERE name = 'crash'"); +$crash_keyword_id or die "Can't find keyword id for 'crash'\n"; + +my $topcrash_keyword_id = $dbh->selectrow_array( + "SELECT id FROM keyworddefs WHERE name = 'topcrash'"); +$topcrash_keyword_id or die "Can't find keyword id for 'topcrash'\n"; + +# main search query +my $bugs = $dbh->selectall_arrayref(" + SELECT bugs.bug_id, bugs.short_desc + FROM bugs LEFT JOIN keywords ON bugs.bug_id = keywords.bug_id + WHERE (keywords.keywordid = ? OR keywords.keywordid = ?) + AND bugs.status_whiteboard NOT REGEXP '\\\\[notacrash\\\\]' + AND bugs.short_desc REGEXP '\\\\[@.+\\\\]' + AND (bugs.cf_crash_signature IS NULL OR bugs.cf_crash_signature = '') + ORDER BY bugs.bug_id", + {'Slice' => {}}, $crash_keyword_id, $topcrash_keyword_id); + +my $bug_count = scalar @$bugs; +$bug_count or die "No bugs were found in matching search criteria.\n"; + +print "Migrating $bug_count bugs to new crash signature field\n"; + +$dbh->bz_start_transaction() if $UPDATE_DB; + +foreach my $bug (@$bugs) { + my $bug_id = $bug->{'bug_id'}; + my $summary = $bug->{'short_desc'}; + + print "Updating bug $bug_id ..."; + + my @signatures; + while ($summary =~ /(\[\@(?:\[.*\]|[^\[])*\])/g) { + push(@signatures, $1); + } + + if (@signatures && $UPDATE_DB) { + my $timestamp = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)'); + $dbh->do("UPDATE bugs SET cf_crash_signature = ? WHERE bug_id = ?", + undef, join("\n", @signatures), $bug_id); + $dbh->do("INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added) " . + "VALUES (?, ?, ?, ?, '', ?)", + undef, $bug_id, $user_id, $timestamp, $field_id, join("\n", @signatures)); + $dbh->do("UPDATE bugs SET delta_ts = ?, lastdiffed = ? WHERE bug_id = ?", + undef, $timestamp, $timestamp, $bug_id); + } + elsif (@signatures) { + print Dumper(\@signatures); + } + + print "done.\n"; +} + +$dbh->bz_commit_transaction() if $UPDATE_DB; diff --git a/contrib/reorg-tools/move_flag_types.pl b/contrib/reorg-tools/move_flag_types.pl new file mode 100644 index 000000000..a75b7f497 --- /dev/null +++ b/contrib/reorg-tools/move_flag_types.pl @@ -0,0 +1,168 @@ +#!/usr/bin/perl +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Initial Developer of the Original Code is Mozilla Foundation +# Portions created by the Initial Developer are Copyright (C) 2011 the +# Initial Developer. All Rights Reserved. +# +#=============================================================================== +# +# FILE: move_flag_types.pl +# +# USAGE: ./move_flag_types.pl +# +# DESCRIPTION: Move current set flag from one type_id to another +# based on product and optionally component. +# +# OPTIONS: --- +# REQUIREMENTS: --- +# BUGS: --- +# NOTES: --- +# AUTHOR: David Lawrence (:dkl), dkl@mozilla.com +# COMPANY: Mozilla Foundation +# VERSION: 1.0 +# CREATED: 08/22/2011 05:18:06 PM +# REVISION: --- +#=============================================================================== + +=head1 NAME + +move_flag_types.pl - Move currently set flags from one type id to another based +on product and optionally component. + +=head1 SYNOPSIS + +This script will move bugs matching a specific product (and optionally a component) +from one flag type id to another if the bug has the flag set to either +, -, or ?. + +./move_flag_types.pl --old-id 4 --new-id 720 --product Firefox --component Installer + +=head1 OPTIONS + +=over + +=item B<--help|-h|?> + +Print a brief help message and exits. + +=item B<--oldid|-o> + +Old flag type id. Use editflagtypes.cgi to determine the type id from the URL. + +=item B<--newid|-n> + +New flag type id. Use editflagtypes.cgi to determine the type id from the URL. + +=item B<--product|-p> + +The product that the bugs most be assigned to. + +=item B<--component|-c> + +Optional: The component of the given product that the bugs must be assigned to. + +=item B<--doit|-d> + +Without this argument, changes are not actually committed to the database. + +=back + +=cut + +use strict; +use warnings; + +use lib '.'; + +use Bugzilla; +use Getopt::Long; +use Pod::Usage; + +my %params; +GetOptions(\%params, 'help|h|?', 'oldid|o=s', 'newid|n=s', + 'product|p=s', 'component|c:s', 'doit|d') or pod2usage(1); + +if ($params{'help'} || !$params{'oldid'} + || !$params{'newid'} || !$params{'product'}) { + pod2usage({ -message => "Missing required argument", + -exitval => 1 }); +} + +# Set defaults +$params{'doit'} ||= 0; +$params{'component'} ||= ''; + +my $dbh = Bugzilla->dbh; + +# Get the flag names +my $old_flag_name = $dbh->selectrow_array( + "SELECT name FROM flagtypes WHERE id = ?", + undef, $params{'oldid'}); +my $new_flag_name = $dbh->selectrow_array( + "SELECT name FROM flagtypes WHERE id = ?", + undef, $params{'newid'}); + +# Find the product id +my $product_id = $dbh->selectrow_array( + "SELECT id FROM products WHERE name = ?", + undef, $params{'product'}); + +# Find the component id if not __ANY__ +my $component_id; +if ($params{'component'}) { + $component_id = $dbh->selectrow_array( + "SELECT id FROM components WHERE name = ? AND product_id = ?", + undef, $params{'component'}, $product_id); +} + +my @query_args = ($params{'oldid'}); + +my $flag_query = "SELECT flags.id AS flag_id, flags.bug_id AS bug_id + FROM flags JOIN bugs ON flags.bug_id = bugs.bug_id + WHERE flags.type_id = ? "; + +if ($component_id) { + # No need to compare against product_id as component_id is already + # tied to a specific product + $flag_query .= "AND bugs.component_id = ?"; + push(@query_args, $component_id); +} +else { + # All bugs for a product regardless of component + $flag_query .= "AND bugs.product_id = ?"; + push(@query_args, $product_id); +} + +my $flags = $dbh->selectall_arrayref($flag_query, undef, @query_args); + +if (@$flags) { + print "Moving '" . scalar @$flags . "' flags " . + "from $old_flag_name (" . $params{'oldid'} . ") " . + "to $new_flag_name (" . $params{'newid'} . ")...\n"; + + if (!$params{'doit'}) { + print "Pass the argument --doit or -d to permanently make changes to the database.\n"; + } + else { + my $flag_update_sth = $dbh->prepare("UPDATE flags SET type_id = ? WHERE id = ?"); + + foreach my $flag (@$flags) { + my ($flag_id, $bug_id) = @$flag; + print "Bug: $bug_id Flag: $flag_id\n"; + $flag_update_sth->execute($params{'newid'}, $flag_id); + } + } +} +else { + print "No flags to move\n"; +} diff --git a/contrib/reorg-tools/movebugs.pl b/contrib/reorg-tools/movebugs.pl new file mode 100644 index 000000000..33156dad7 --- /dev/null +++ b/contrib/reorg-tools/movebugs.pl @@ -0,0 +1,151 @@ +#!/usr/bin/perl -w +use strict; + +use Cwd 'abs_path'; +use File::Basename; +BEGIN { + my $root = abs_path(dirname(__FILE__) . '/../..'); + chdir($root); +} +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Util; + +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 4) { + die <<USAGE; +Usage: movebugs.pl <old-product> <old-component> <new-product> <new-component> + +Eg. movebugs.pl mozilla.org bmo bugzilla.mozilla.org admin +Will move all bugs in the mozilla.org:bmo component to the +bugzilla.mozilla.org:admin component. + +The new product must have matching versions and milestones from the old +product. +USAGE +} + +my ($old_product, $old_component, $new_product, $new_component) = @ARGV; + +my $dbh = Bugzilla->dbh; + +my $old_product_id = $dbh->selectrow_array( + "SELECT id FROM products WHERE name=?", + undef, $old_product); +$old_product_id + or die "Can't find product ID for '$old_product'.\n"; + +my $old_component_id = $dbh->selectrow_array( + "SELECT id FROM components WHERE name=? AND product_id=?", + undef, $old_component, $old_product_id); +$old_component_id + or die "Can't find component ID for '$old_component'.\n"; + +my $new_product_id = $dbh->selectrow_array( + "SELECT id FROM products WHERE name=?", + undef, $new_product); +$new_product_id + or die "Can't find product ID for '$new_product'.\n"; + +my $new_component_id = $dbh->selectrow_array( + "SELECT id FROM components WHERE name=? AND product_id=?", + undef, $new_component, $new_product_id); +$new_component_id + or die "Can't find component ID for '$new_component'.\n"; + +my $product_field_id = $dbh->selectrow_array( + "SELECT id FROM fielddefs WHERE name = 'product'"); +$product_field_id + or die "Can't find field ID for 'product' field\n"; +my $component_field_id = $dbh->selectrow_array( + "SELECT id FROM fielddefs WHERE name = 'component'"); +$component_field_id + or die "Can't find field ID for 'component' field\n"; + +my $user_id = $dbh->selectrow_array( + "SELECT userid FROM profiles WHERE login_name='nobody\@mozilla.org'"); +$user_id + or die "Can't find user ID for 'nobody\@mozilla.org'\n"; + +$dbh->bz_start_transaction(); + +# build list of bugs +my $ra_ids = $dbh->selectcol_arrayref( + "SELECT bug_id FROM bugs WHERE product_id=? AND component_id=?", + undef, $old_product_id, $old_component_id); +my $bug_count = scalar @$ra_ids; +$bug_count + or die "No bugs were found in '$old_component'\n"; +my $where_sql = 'bug_id IN (' . join(',', @$ra_ids) . ')'; + +# check versions +my @missing_versions; +my $ra_versions = $dbh->selectcol_arrayref( + "SELECT DISTINCT version FROM bugs WHERE $where_sql"); +foreach my $version (@$ra_versions) { + my $has_version = $dbh->selectrow_array( + "SELECT 1 FROM versions WHERE product_id=? AND value=?", + undef, $new_product_id, $version); + push @missing_versions, $version unless $has_version; +} + +# check milestones +my @missing_milestones; +my $ra_milestones = $dbh->selectcol_arrayref( + "SELECT DISTINCT target_milestone FROM bugs WHERE $where_sql"); +foreach my $milestone (@$ra_milestones) { + my $has_milestone = $dbh->selectrow_array( + "SELECT 1 FROM milestones WHERE product_id=? AND value=?", + undef, $new_product_id, $milestone); + push @missing_milestones, $milestone unless $has_milestone; +} + +my $missing_error = ''; +if (@missing_versions) { + $missing_error .= "'$new_product' is missing the following version(s):\n " . + join("\n ", @missing_versions) . "\n"; +} +if (@missing_milestones) { + $missing_error .= "'$new_product' is missing the following milestone(s):\n " . + join("\n ", @missing_milestones) . "\n"; +} +die $missing_error if $missing_error; + +# confirmation +print <<EOF; +About to move $bug_count bugs +From '$old_product' : '$old_component' +To '$new_product' : '$new_component' + +Press <Ctrl-C> to stop or <Enter> to continue... +EOF +getc(); + +print "Moving $bug_count bugs from $old_product:$old_component to $new_product:$new_component\n"; + +# update bugs +$dbh->do( + "UPDATE bugs SET product_id=?, component_id=? WHERE $where_sql", + undef, $new_product_id, $new_component_id); + +# touch bugs +$dbh->do("UPDATE bugs SET delta_ts=NOW() WHERE $where_sql"); +$dbh->do("UPDATE bugs SET lastdiffed=NOW() WHERE $where_sql"); + +# update bugs_activity +$dbh->do( + "INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added) + SELECT bug_id, ?, delta_ts, ?, ?, ? FROM bugs WHERE $where_sql", + undef, + $user_id, $product_field_id, $old_product, $new_product); +$dbh->do( + "INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added) + SELECT bug_id, ?, delta_ts, ?, ?, ? FROM bugs WHERE $where_sql", + undef, + $user_id, $component_field_id, $old_component, $new_component); + +$dbh->bz_commit_transaction(); + diff --git a/contrib/reorg-tools/movecomponent.pl b/contrib/reorg-tools/movecomponent.pl new file mode 100644 index 000000000..8f8bc0abc --- /dev/null +++ b/contrib/reorg-tools/movecomponent.pl @@ -0,0 +1,193 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Gervase Markham <gerv@gerv.net> + +# See also https://bugzilla.mozilla.org/show_bug.cgi?id=119569 +# + +use strict; + +use Cwd 'abs_path'; +use File::Basename; +BEGIN { + my $root = abs_path(dirname(__FILE__) . '/../..'); + chdir($root); +} +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Util; + +sub usage() { + print <<USAGE; +Usage: movecomponent.pl <oldproduct> <newproduct> <component> <doit> + +E.g.: movecomponent.pl ReplicationEngine FoodReplicator SeaMonkey +will move the component "SeaMonkey" from the product "ReplicationEngine" +to the product "FoodReplicator". + +Important: You must make sure the milestones and versions of the bugs in the +component are available in the new product. See syncmsandversions.pl. + +Pass in a true value for "doit" to make the database changes permament. +USAGE + + exit(1); +} + +############################################################################# +# MAIN CODE +############################################################################# + +# This is a pure command line script. +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 3) { + usage(); + exit(); +} + +my ($oldproduct, $newproduct, $component, $doit) = @ARGV; + +my $dbh = Bugzilla->dbh; + +$dbh->{'AutoCommit'} = 0 unless $doit; # Turn off autocommit by default + +# Find product IDs +my $oldprodid = $dbh->selectrow_array("SELECT id FROM products WHERE name = ?", + undef, $oldproduct); +if (!$oldprodid) { + print "Can't find product ID for '$oldproduct'.\n"; + exit(1); +} + +my $newprodid = $dbh->selectrow_array("SELECT id FROM products WHERE name = ?", + undef, $newproduct); +if (!$newprodid) { + print "Can't find product ID for '$newproduct'.\n"; + exit(1); +} + +# Find component ID +my $compid = $dbh->selectrow_array("SELECT id FROM components + WHERE name = ? AND product_id = ?", + undef, $component, $oldprodid); +if (!$compid) { + print "Can't find component ID for '$component' in product " . + "'$oldproduct'.\n"; + exit(1); +} + +my $fieldid = $dbh->selectrow_array("SELECT id FROM fielddefs + WHERE name = 'product'"); +if (!$fieldid) { + print "Can't find field ID for 'product' field!\n"; + exit(1); +} + +# check versions +my @missing_versions; +my $ra_versions = $dbh->selectcol_arrayref( + "SELECT DISTINCT version FROM bugs WHERE component_id = ?", + undef, $compid); +foreach my $version (@$ra_versions) { + my $has_version = $dbh->selectrow_array( + "SELECT 1 FROM versions WHERE product_id = ? AND value = ?", + undef, $newprodid, $version); + push @missing_versions, $version unless $has_version; +} + +# check milestones +my @missing_milestones; +my $ra_milestones = $dbh->selectcol_arrayref( + "SELECT DISTINCT target_milestone FROM bugs WHERE component_id = ?", + undef, $compid); +foreach my $milestone (@$ra_milestones) { + my $has_milestone = $dbh->selectrow_array( + "SELECT 1 FROM milestones WHERE product_id=? AND value=?", + undef, $newprodid, $milestone); + push @missing_milestones, $milestone unless $has_milestone; +} + +my $missing_error = ''; +if (@missing_versions) { + $missing_error .= "'$newproduct' is missing the following version(s):\n " . + join("\n ", @missing_versions) . "\n"; +} +if (@missing_milestones) { + $missing_error .= "'$newproduct' is missing the following milestone(s):\n " . + join("\n ", @missing_milestones) . "\n"; +} +die $missing_error if $missing_error; + +# confirmation +print <<EOF; +About to move the component '$component' +From '$oldproduct' +To '$newproduct' + +Press <Ctrl-C> to stop or <Enter> to continue... +EOF +getc(); + +print "Moving '$component' from '$oldproduct' to '$newproduct'...\n\n"; +$dbh->bz_start_transaction() if $doit; + +# Bugs table +$dbh->do("UPDATE bugs SET product_id = ? WHERE component_id = ?", + undef, + ($newprodid, $compid)); + +# Flags tables +$dbh->do("UPDATE flaginclusions SET product_id = ? WHERE component_id = ?", + undef, + ($newprodid, $compid)); + +$dbh->do("UPDATE flagexclusions SET product_id = ? WHERE component_id = ?", + undef, + ($newprodid, $compid)); + +# Components +$dbh->do("UPDATE components SET product_id = ? WHERE id = ?", + undef, + ($newprodid, $compid)); + +# Mark bugs as touched +$dbh->do("UPDATE bugs SET delta_ts = NOW() + WHERE component_id = ?", undef, $compid); +$dbh->do("UPDATE bugs SET lastdiffed = NOW() + WHERE component_id = ?", undef, $compid); + +# Update bugs_activity +my $userid = 1; # nobody@mozilla.org + +$dbh->do("INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, + added) + SELECT bug_id, ?, delta_ts, ?, ?, ? + FROM bugs WHERE component_id = ?", + undef, + ($userid, $fieldid, $oldproduct, $newproduct, $compid)); + +$dbh->bz_commit_transaction() if $doit; + +exit(0); + diff --git a/contrib/reorg-tools/syncflags.pl b/contrib/reorg-tools/syncflags.pl new file mode 100644 index 000000000..6c5b8293a --- /dev/null +++ b/contrib/reorg-tools/syncflags.pl @@ -0,0 +1,86 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Gervase Markham <gerv@gerv.net> + +# See also https://bugzilla.mozilla.org/show_bug.cgi?id=119569 + +use strict; + +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; + +sub usage() { + print <<USAGE; +Usage: syncflags.pl <srcproduct> <tgtproduct> + +E.g.: syncflags.pl FoodReplicator SeaMonkey +will copy any flag inclusions (only) for the product "FoodReplicator" +so matching inclusions exist for the product "SeaMonkey". This script is +normally used prior to moving components from srcproduct to tgtproduct. +USAGE + + exit(1); +} + +############################################################################# +# MAIN CODE +############################################################################# + +# This is a pure command line script. +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 2) { + usage(); + exit(); +} + +my ($srcproduct, $tgtproduct) = @ARGV; + +my $dbh = Bugzilla->dbh; + +# Find product IDs +my $srcprodid = $dbh->selectrow_array("SELECT id FROM products WHERE name = ?", + undef, $srcproduct); +if (!$srcprodid) { + print "Can't find product ID for '$srcproduct'.\n"; + exit(1); +} + +my $tgtprodid = $dbh->selectrow_array("SELECT id FROM products WHERE name = ?", + undef, $tgtproduct); +if (!$tgtprodid) { + print "Can't find product ID for '$tgtproduct'.\n"; + exit(1); +} + +$dbh->do("INSERT INTO flaginclusions(component_id, type_id, product_id) + SELECT fi1.component_id, fi1.type_id, ? FROM flaginclusions fi1 + LEFT JOIN flaginclusions fi2 + ON fi1.type_id = fi2.type_id + AND fi2.product_id = ? + WHERE fi1.product_id = ? + AND fi2.type_id IS NULL", + undef, + $tgtprodid, $tgtprodid, $srcprodid); + +exit(0); diff --git a/contrib/reorg-tools/syncmsandversions.pl b/contrib/reorg-tools/syncmsandversions.pl new file mode 100644 index 000000000..b25b3348b --- /dev/null +++ b/contrib/reorg-tools/syncmsandversions.pl @@ -0,0 +1,107 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Gervase Markham <gerv@gerv.net> + +# See also https://bugzilla.mozilla.org/show_bug.cgi?id=119569 + +use strict; + +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; + +sub usage() { + print <<USAGE; +Usage: syncmsandversions.pl <srcproduct> <tgtproduct> + +E.g.: syncmsandversions.pl FoodReplicator SeaMonkey +will copy any versions and milstones in the product "FoodReplicator" +which do not exist in product "SeaMonkey" into it. This script is normally +used prior to moving components from srcproduct to tgtproduct. +USAGE + + exit(1); +} + +############################################################################# +# MAIN CODE +############################################################################# + +# This is a pure command line script. +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 2) { + usage(); + exit(); +} + +my ($srcproduct, $tgtproduct) = @ARGV; + +my $dbh = Bugzilla->dbh; + +# Find product IDs +my $srcprodid = $dbh->selectrow_array("SELECT id FROM products WHERE name = ?", + undef, $srcproduct); +if (!$srcprodid) { + print "Can't find product ID for '$srcproduct'.\n"; + exit(1); +} + +my $tgtprodid = $dbh->selectrow_array("SELECT id FROM products WHERE name = ?", + undef, $tgtproduct); +if (!$tgtprodid) { + print "Can't find product ID for '$tgtproduct'.\n"; + exit(1); +} + +#$dbh->bz_start_transaction(); + +$dbh->do("INSERT INTO milestones(value, sortkey, product_id) + SELECT m1.value, m1.sortkey, ? FROM milestones m1 + LEFT JOIN milestones m2 ON m1.value = m2.value AND + m2.product_id = ? + WHERE m1.product_id = ? AND m2.value IS NULL", + undef, + $tgtprodid, $tgtprodid, $srcprodid); + +$dbh->do("INSERT INTO versions(value, product_id) + SELECT v1.value, ? FROM versions v1 + LEFT JOIN versions v2 ON v1.value = v2.value AND + v2.product_id = ? + WHERE v1.product_id = ? AND v2.value IS NULL", + undef, + $tgtprodid, $tgtprodid, $srcprodid); + +$dbh->do("INSERT INTO group_control_map (group_id, product_id, entry, membercontrol, othercontrol, canedit, editcomponents, editbugs, canconfirm) + SELECT g1.group_id, ?, g1.entry, g1.membercontrol, g1.othercontrol, g1.canedit, g1.editcomponents, g1.editbugs, g1.canconfirm + FROM group_control_map g1 + LEFT JOIN group_control_map g2 ON g1.product_id = ? AND + g2.product_id = ? AND + g1.group_id = g2.group_id + WHERE g1.product_id = ? AND g2.group_id IS NULL", + undef, + $tgtprodid, $srcprodid, $tgtprodid, $srcprodid); + +#$dbh->bz_commit_transaction(); + +exit(0); + diff --git a/contrib/sanitizeme.pl b/contrib/sanitizeme.pl new file mode 100644 index 000000000..362700be0 --- /dev/null +++ b/contrib/sanitizeme.pl @@ -0,0 +1,176 @@ +#!/usr/bin/perl -wT +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is the Mozilla +# Corporation. Portions created by Mozilla are +# Copyright (C) 2006 Mozilla Foundation. All Rights Reserved. +# +# Contributor(s): Myk Melez <myk@mozilla.org> +# Alex Brugh <alex@cs.umn.edu> +# Dave Miller <justdave@mozilla.com> +# Byron Jones <glob@mozilla.com> + +use strict; + +use lib qw(.); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Util; + +use Getopt::Long; + +my $dbh = Bugzilla->dbh; + +# This SQL is designed to sanitize a copy of a Bugzilla database so that it +# doesn't contain any information that can't be viewed from a web browser by +# a user who is not logged in. + +# Last validated against Bugzilla version 4.0 + +my ($dry_run, $from_cron, $keep_attachments, $keep_groups, + $keep_passwords, $keep_insider, $trace) = (0, 0, 0, '', 0, 0, 0); +my $keep_groups_sql = ''; + +GetOptions( + "dry-run" => \$dry_run, + "from-cron" => \$from_cron, + "keep-attachments" => \$keep_attachments, + "keep-passwords" => \$keep_passwords, + "keep-insider" => \$keep_insider, + "keep-groups:s" => \$keep_groups, + "trace" => \$trace, +) or exit; + +if ($keep_groups ne '') { + my @groups; + foreach my $group_id (split(/\s*,\s*/, $keep_groups)) { + my $group; + if ($group_id =~ /\D/) { + $group = Bugzilla::Group->new({ name => $group_id }); + } else { + $group = Bugzilla::Group->new($group_id); + } + die "Invalid group '$group_id'\n" unless $group; + push @groups, $group->id; + } + $keep_groups_sql = "NOT IN (" . join(",", @groups) . ")"; +} + +$dbh->{TraceLevel} = 1 if $trace; + +if ($dry_run) { + print "** dry run : no changes to the database will be made **\n"; + $dbh->bz_start_transaction(); +} +eval { + delete_non_public_products(); + delete_secure_bugs(); + delete_insider_comments() unless $keep_insider; + delete_security_groups(); + delete_sensitive_user_data(); + delete_attachment_data() unless $keep_attachments; + print "All done!\n"; + $dbh->bz_rollback_transaction() if $dry_run; +}; +if ($@) { + $dbh->bz_rollback_transaction() if $dry_run; + die "$@" if $@; +} + +sub delete_non_public_products { + # Delete all non-public products, and all data associated with them + my @products = Bugzilla::Product->get_all(); + my $mandatory = CONTROLMAPMANDATORY; + foreach my $product (@products) { + # if there are any mandatory groups on the product, nuke it and + # everything associated with it (including the bugs) + Bugzilla->params->{'allowbugdeletion'} = 1; # override this in memory for now + my $mandatorygroups = $dbh->selectcol_arrayref("SELECT group_id FROM group_control_map WHERE product_id = ? AND (membercontrol = $mandatory)", undef, $product->id); + if (0 < scalar(@$mandatorygroups)) { + print "Deleting product '" . $product->name . "'...\n"; + $product->remove_from_db(); + } + } +} + +sub delete_secure_bugs { + # Delete all data for bugs in security groups. + my $buglist = $dbh->selectall_arrayref( + $keep_groups + ? "SELECT DISTINCT bug_id FROM bug_group_map WHERE group_id $keep_groups_sql" + : "SELECT DISTINCT bug_id FROM bug_group_map" + ); + $|=1; # disable buffering so the bug progress counter works + my $numbugs = scalar(@$buglist); + my $bugnum = 0; + print "Deleting $numbugs bugs in " . ($keep_groups ? 'non-' : '') . "security groups...\n"; + foreach my $row (@$buglist) { + my $bug_id = $row->[0]; + $bugnum++; + print "\r$bugnum/$numbugs" unless $from_cron; + my $bug = new Bugzilla::Bug($bug_id); + $bug->remove_from_db(); + } + print "\rDone \n" unless $from_cron; +} + +sub delete_insider_comments { + # Delete all 'insidergroup' comments and attachments + print "Deleting 'insidergroup' comments and attachments...\n"; + $dbh->do("DELETE FROM longdescs WHERE isprivate = 1"); + $dbh->do("DELETE attach_data FROM attachments JOIN attach_data ON attachments.attach_id = attach_data.id WHERE attachments.isprivate = 1"); + $dbh->do("DELETE FROM attachments WHERE isprivate = 1"); + $dbh->do("UPDATE bugs_fulltext SET comments = comments_noprivate"); +} + +sub delete_security_groups { + # Delete all security groups. + print "Deleting " . ($keep_groups ? 'non-' : '') . "security groups...\n"; + $dbh->do("DELETE user_group_map FROM groups JOIN user_group_map ON groups.id = user_group_map.group_id WHERE groups.isbuggroup = 1"); + $dbh->do("DELETE group_group_map FROM groups JOIN group_group_map ON (groups.id = group_group_map.member_id OR groups.id = group_group_map.grantor_id) WHERE groups.isbuggroup = 1"); + $dbh->do("DELETE group_control_map FROM groups JOIN group_control_map ON groups.id = group_control_map.group_id WHERE groups.isbuggroup = 1"); + $dbh->do("UPDATE flagtypes LEFT JOIN groups ON flagtypes.grant_group_id = groups.id SET grant_group_id = NULL WHERE groups.isbuggroup = 1"); + $dbh->do("UPDATE flagtypes LEFT JOIN groups ON flagtypes.request_group_id = groups.id SET request_group_id = NULL WHERE groups.isbuggroup = 1"); + if ($keep_groups) { + $dbh->do("DELETE FROM groups WHERE isbuggroup = 1 AND id $keep_groups_sql"); + } else { + $dbh->do("DELETE FROM groups WHERE isbuggroup = 1"); + } +} + +sub delete_sensitive_user_data { + # Remove sensitive user account data. + print "Deleting sensitive user account data...\n"; + $dbh->do("UPDATE profiles SET cryptpassword = 'deleted'") unless $keep_passwords; + $dbh->do("DELETE FROM profiles_activity"); + $dbh->do("DELETE FROM profile_search"); + $dbh->do("DELETE FROM namedqueries"); + $dbh->do("DELETE FROM tokens"); + $dbh->do("DELETE FROM logincookies"); + $dbh->do("DELETE FROM login_failure"); + $dbh->do("DELETE FROM ts_error"); + $dbh->do("DELETE FROM ts_exitstatus"); + $dbh->do("DELETE FROM ts_funcmap"); + $dbh->do("DELETE FROM ts_job"); + $dbh->do("DELETE FROM ts_note"); +} + +sub delete_attachment_data { + # Delete unnecessary attachment data. + print "Removing attachment data to preserve disk space...\n"; + $dbh->do("UPDATE attach_data SET thedata = ''"); +} + diff --git a/contrib/verify-user.pl b/contrib/verify-user.pl new file mode 100644 index 000000000..d12cd745f --- /dev/null +++ b/contrib/verify-user.pl @@ -0,0 +1,129 @@ +#!/usr/bin/perl -wT +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Myk Melez <myk@mozilla.org> +# Dave Miller <justdave@bugzilla.org> + +# See if a user account has ever done anything + +# ./verify-user.pl foo@baz.com + +use strict; + +use lib qw(.); + +use Bugzilla; +use Bugzilla::Util; +use Bugzilla::DB; +use Bugzilla::Constants; + +# Make sure accounts were specified on the command line and exist. +my $user = $ARGV[0] || die "You must specify an user.\n"; +my $dbh = Bugzilla->dbh; +my $sth; + +#$sth = $dbh->prepare("SELECT name, count(*) as qty from bugs, products where reporter=198524 and product_id=products.id group by name order by qty desc"); +#$sth->execute(); +#my $results = $sth->fetchall_arrayref(); +#use Data::Dumper; +#print Data::Dumper::Dumper($results); +#exit; + +trick_taint($user); +if ($user =~ /^\d+$/) { # user ID passed instead of email + $sth = $dbh->prepare('SELECT login_name FROM profiles WHERE userid = ?'); + $sth->execute($user); + ($user) = $sth->fetchrow_array || die "The user with ID $ARGV[0] does not exist.\n"; + print "User $ARGV[0]'s login name is $user.\n"; +} +$sth = $dbh->prepare("SELECT userid FROM profiles WHERE login_name = ?"); +$sth->execute($user); +my ($user_id) = $sth->fetchrow_array || die "The user $user does not exist.\n"; + +print "${user}'s ID is $user_id.\n"; + +$sth = $dbh->prepare("SELECT DISTINCT ipaddr FROM logincookies WHERE userid = ?"); +$sth->execute($user_id); +my $iplist = $sth->fetchall_arrayref; +if (@$iplist > 0) { + print "This user has recently connected from the following IP addresses:\n"; + foreach my $ip (@$iplist) { + print $$ip[0] . "\n"; + } +} + + +# A list of tables and columns to be checked. +my $columns = { + attachments => ['submitter_id'] , + bugs => ['assigned_to', 'reporter', 'qa_contact'] , + bugs_activity => ['who'] , + cc => ['who'] , + components => ['initialowner', 'initialqacontact'] , + flags => ['setter_id', 'requestee_id'] , + logincookies => ['userid'] , + longdescs => ['who'] , + namedqueries => ['userid'] , + profiles_activity => ['userid', 'who'] , + quips => ['userid'] , + series => ['creator'] , + tokens => ['userid'] , + user_group_map => ['user_id'] , + votes => ['who'] , + watch => ['watcher', 'watched'] , + +}; + +my $fields = 0; +# Check records for user. +foreach my $table (keys(%$columns)) { + foreach my $column (@{$columns->{$table}}) { + $sth = $dbh->prepare("SELECT COUNT(*) FROM $table WHERE $column = ?"); + if ($table eq 'user_group_map') { + $sth = $dbh->prepare("SELECT COUNT(*) FROM $table WHERE $column = ? AND grant_type = " . GRANT_DIRECT); + } + $sth->execute($user_id); + my ($val) = $sth->fetchrow_array; + $fields++ if $val; + print "$table.$column: $val\n" if $val; + } +} + +print "The user is mentioned in $fields fields.\n"; + +if ($::ARGV[1] && $::ARGV[1] eq '-r') { + if ($fields == 0) { + $sth = $dbh->prepare("SELECT login_name FROM profiles WHERE login_name = ?"); + my $count = 0; + print "Finding an unused recycle ID"; + do { + $count++; + $sth->execute(sprintf("reuseme%03d\@bugzilla.org", $count)); + print "."; + } while (my ($match) = $sth->fetchrow_array()); + printf "\nUsing reuseme%03d\@bugzilla.org.\n", $count; + $dbh->do("DELETE FROM user_group_map WHERE user_id=?",undef,$user_id); + $dbh->do("UPDATE profiles SET realname='', cryptpassword='randomgarbage' WHERE userid=?",undef,$user_id); + $dbh->do("UPDATE profiles SET login_name=? WHERE userid=?",undef,sprintf("reuseme%03d\@bugzilla.org",$count),$user_id); + } + else { + print "Account has been used, so not recycling.\n"; + } +} |