Commit 3a17775f authored by Per Cederqvist's avatar Per Cederqvist Committed by root
parents 851b4ae3 e863cc79
No preview for this file type
d1a96d7f578241975efd41d87462bc776b3a505a
\ No newline at end of file
737bc170933d5c02bf4636103782e8e46a31d96b
\ No newline at end of file
language: perl
perl:
- 5.10
- 5.12
env:
- TEST_SUITE=sanity
- TEST_SUITE=docs
- TEST_SUITE=webservices DB=mysql
- TEST_SUITE=selenium DB=mysql
- TEST_SUITE=webservices DB=pg
- TEST_SUITE=selenium DB=pg
matrix:
exclude:
- perl: 5.12
env: TEST_SUITE=docs
- perl: 5.10
env: TEST_SUITE=webservices DB=mysql
- perl: 5.12
env: TEST_SUITE=selenium DB=mysql
- perl: 5.10
env: TEST_SUITE=webservices DB=pg
- perl: 5.12
env: TEST_SUITE=selenium DB=pg
before_install:
- git clone https://github.com/bugzilla/qa.git -b 4.4 qa
install: true
script: ./qa/travis.sh
after_failure:
- sudo cat /var/log/apache2/error.log
notifications:
irc:
channels:
- "irc.mozilla.org#qa-bugzilla"
- "irc.mozilla.org#bugzilla"
template:
- "Bugzilla %{branch} : %{author} : %{message}"
- "Commit Message : %{commit_message}"
- "Commit Link : %{compare_url}"
- "Build Link : %{build_url}"
on_success: change
on_failure: always
......@@ -67,7 +67,7 @@ use constant SHUTDOWNHTML_RETRY_AFTER => 3600;
# Global Code
#####################################################################
# $::SIG{__DIE__} = i_am_cgi() ? \&CGI::Carp::confess : \&Carp::confess;
#$::SIG{__DIE__} = i_am_cgi() ? \&CGI::Carp::confess : \&Carp::confess;
# Note that this is a raw subroutine, not a method, so $class isn't available.
sub init_page {
......
......@@ -895,16 +895,12 @@ sub update {
}
# Record changes in the activity table.
my $sth = $dbh->prepare('INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when,
fieldid, removed, added)
VALUES (?, ?, ?, ?, ?, ?, ?)');
require Bugzilla::Bug;
foreach my $field (keys %$changes) {
my $change = $changes->{$field};
$field = "attachments.$field" unless $field eq "flagtypes.name";
my $fieldid = get_field_id($field);
$sth->execute($self->bug_id, $self->id, $user->id, $timestamp,
$fieldid, $change->[0], $change->[1]);
Bugzilla::Bug::LogActivityEntry($self->bug_id, $field, $change->[0],
$change->[1], $user->id, $timestamp, undef, $self->id);
}
if (scalar(keys %$changes)) {
......
......@@ -55,7 +55,7 @@ sub get_login_info {
ThrowUserError('auth_untrusted_request', { login => $login });
}
if (!$login || !$password || !$valid) {
if (!defined($login) || !defined($password) || !$valid) {
return { failure => AUTH_NODATA };
}
......
......@@ -68,7 +68,9 @@ sub check_credentials {
# whatever hashing system we're using now.
my $current_algorithm = PASSWORD_DIGEST_ALGORITHM;
if ($real_password_crypted !~ /{\Q$current_algorithm\E}$/) {
$user->set_password($password);
# We can't call $user->set_password because we don't want the password
# complexity rules to apply here.
$user->{cryptpassword} = bz_crypt($password);
$user->update();
}
......
......@@ -246,7 +246,6 @@ use constant MAX_LINE_LENGTH => 254;
# use.)
use constant FIELD_MAP => {
blocks => 'blocked',
cc_accessible => 'cclist_accessible',
commentprivacy => 'comment_is_private',
creation_time => 'creation_ts',
creator => 'reporter',
......@@ -3939,7 +3938,8 @@ sub get_activity {
# Update the bugs_activity table to reflect changes made in bugs.
sub LogActivityEntry {
my ($i, $col, $removed, $added, $whoid, $timestamp, $comment_id) = @_;
my ($i, $col, $removed, $added, $whoid, $timestamp, $comment_id,
$attach_id) = @_;
my $dbh = Bugzilla->dbh;
# in the case of CCs, deps, and keywords, there's a possibility that someone
# might try to add or remove a lot of them at once, which might take more
......@@ -3964,10 +3964,13 @@ sub LogActivityEntry {
trick_taint($addstr);
trick_taint($removestr);
my $fieldid = get_field_id($col);
$dbh->do("INSERT INTO bugs_activity
(bug_id, who, bug_when, fieldid, removed, added, comment_id)
VALUES (?, ?, ?, ?, ?, ?, ?)",
undef, ($i, $whoid, $timestamp, $fieldid, $removestr, $addstr, $comment_id));
$dbh->do(
"INSERT INTO bugs_activity
(bug_id, who, bug_when, fieldid, removed, added, comment_id, attach_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
undef,
($i, $whoid, $timestamp, $fieldid, $removestr, $addstr, $comment_id,
$attach_id));
}
}
......
......@@ -182,7 +182,8 @@ use Memoize;
# CONSTANTS
#
# Bugzilla version
use constant BUGZILLA_VERSION => "4.4.4";
use constant BUGZILLA_VERSION => "4.4.5";
# Location of the remote and local XML files to track new releases.
use constant REMOTE_FILE => 'http://updates.bugzilla.org/bugzilla-update.xml';
......
......@@ -196,6 +196,12 @@ use constant DEFAULT_FIELDS => (
buglist => 1},
{name => 'qa_contact', desc => 'QAContact', in_new_bugmail => 1,
buglist => 1},
{name => 'assigned_to_realname', desc => 'AssignedToName',
in_new_bugmail => 0, buglist => 1},
{name => 'reporter_realname', desc => 'ReportedByName',
in_new_bugmail => 0, buglist => 1},
{name => 'qa_contact_realname', desc => 'QAContactName',
in_new_bugmail => 0, buglist => 1},
{name => 'cc', desc => 'CC', in_new_bugmail => 1},
{name => 'dependson', desc => 'Depends on', in_new_bugmail => 1,
is_numeric => 1},
......
......@@ -205,14 +205,20 @@ sub update_localconfig {
# a 256-character string for site_wide_secret.
$value = undef if ($name eq 'site_wide_secret' and defined $value
and length($value) == 256);
if (!defined $value) {
push(@new_vars, $name);
$var->{default} = &{$var->{default}} if ref($var->{default}) eq 'CODE';
if (exists $answer->{$name}) {
$localconfig->{$name} = $answer->{$name};
}
else {
# If the user did not supply an answers file, then they get
# notified about every variable that gets added. If there was
# an answer file, then we don't notify about site_wide_secret
# because we assume the intent was to auto-generate it anyway.
if (!scalar(keys %$answer) || $name ne 'site_wide_secret') {
push(@new_vars, $name);
}
$localconfig->{$name} = $var->{default};
}
}
......
......@@ -368,6 +368,12 @@ sub OPTIONAL_MODULES {
version => 0,
feature => ['jobqueue'],
},
{
package => 'File-Slurp',
module => 'File::Slurp',
version => '9999.13',
feature => ['jobqueue'],
},
# mod_perl
{
......
......@@ -222,6 +222,9 @@ use constant OPERATOR_FIELD_OVERRIDE => {
assigned_to => {
_non_changed => \&_user_nonchanged,
},
assigned_to_realname => {
_non_changed => \&_user_nonchanged,
},
cc => {
_non_changed => \&_user_nonchanged,
},
......@@ -231,6 +234,9 @@ use constant OPERATOR_FIELD_OVERRIDE => {
reporter => {
_non_changed => \&_user_nonchanged,
},
reporter_realname => {
_non_changed => \&_user_nonchanged,
},
'requestees.login_name' => {
_non_changed => \&_user_nonchanged,
},
......@@ -240,7 +246,10 @@ use constant OPERATOR_FIELD_OVERRIDE => {
qa_contact => {
_non_changed => \&_user_nonchanged,
},
qa_contact_realname => {
_non_changed => \&_user_nonchanged,
},
# General Bug Fields
alias => { _non_changed => \&_nullable },
'attach_data.thedata' => MULTI_SELECT_OVERRIDE,
......@@ -520,9 +529,6 @@ sub COLUMNS {
# of short_short_desc.)
my %columns = (
relevance => { title => 'Relevance' },
assigned_to_realname => { title => 'Assignee' },
reporter_realname => { title => 'Reporter' },
qa_contact_realname => { title => 'QA Contact' },
);
# Next we define columns that have special SQL instead of just something
......@@ -575,7 +581,7 @@ sub COLUMNS {
$sql = $dbh->sql_string_until($sql, $dbh->quote('@'));
}
$special_sql{$col} = $sql;
$columns{"${col}_realname"}->{name} = "map_${col}.realname";
$special_sql{"${col}_realname"} = "map_${col}.realname";
}
foreach my $col (@id_fields) {
......@@ -1968,6 +1974,13 @@ sub _quote_unless_numeric {
sub build_subselect {
my ($outer, $inner, $table, $cond, $negate) = @_;
if ($table =~ /\battach_data\b/) {
# It takes a long time to scan the whole attach_data table
# unconditionally, so we return the subselect and let the DB optimizer
# restrict the search based on other search criteria.
my $not = $negate ? "NOT" : "";
return "$outer $not IN (SELECT DISTINCT $inner FROM $table WHERE $cond)";
}
# Execute subselects immediately to avoid dependent subqueries, which are
# large performance hits on MySql
my $q = "SELECT DISTINCT $inner FROM $table WHERE $cond";
......@@ -2283,6 +2296,20 @@ sub _user_nonchanged {
if ($args->{value_is_id}) {
$null_alternate = 0;
}
elsif (substr($field, -9) eq '_realname') {
my $as = "name_${field}_$chart_id";
# For fields with periods in their name.
$as =~ s/\./_/;
my $join = {
table => 'profiles',
as => $as,
from => substr($args->{full_field}, 0, -9),
to => 'userid',
join => (!$is_in_other_table and !$is_nullable) ? 'INNER' : undef,
};
push(@$joins, $join);
$args->{full_field} = "$as.realname";
}
else {
my $as = "name_${field}_$chart_id";
# For fields with periods in their name.
......@@ -2297,7 +2324,7 @@ sub _user_nonchanged {
push(@$joins, $join);
$args->{full_field} = "$as.login_name";
}
# We COALESCE fields that can be NULL, to make "not"-style operators
# continue to work properly. For example, "qa_contact is not equal to bob"
# should also show bugs where the qa_contact is NULL. With COALESCE,
......
......@@ -628,13 +628,13 @@ sub bz_crypt {
$algorithm = $1;
}
# Wide characters cause crypt and Digest to die.
if (Bugzilla->params->{'utf8'}) {
utf8::encode($password) if utf8::is_utf8($password);
}
my $crypted_password;
if (!$algorithm) {
# Wide characters cause crypt to die
if (Bugzilla->params->{'utf8'}) {
utf8::encode($password) if utf8::is_utf8($password);
}
# Crypt the password.
$crypted_password = crypt($password, $salt);
......
......@@ -77,8 +77,9 @@ sub response {
# Implement JSONP.
if (my $callback = $self->_bz_callback) {
my $content = $response->content;
$response->content("$callback($content)");
# Prepend the JSONP response with /**/ in order to protect
# against possible encoding attacks (e.g., affecting Flash).
$response->content("/**/$callback($content)");
}
# Use $cgi->header properly instead of just printing text directly.
......
#!/usr/bin/perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
use 5.10.1;
use strict;
use warnings;
use FindBin qw($RealBin);
use lib ($RealBin, "$RealBin/lib");
use Module::Build 0.36_14;
use Bugzilla::Install::Requirements qw(REQUIRED_MODULES OPTIONAL_MODULES);
use Bugzilla::Constants qw(BUGZILLA_VERSION);
sub requires {
my $requirements = REQUIRED_MODULES();
my $hrequires = {};
foreach my $module (@$requirements) {
$hrequires->{$module->{module}} = $module->{version};
}
return $hrequires;
};
sub build_requires {
return requires();
}
sub recommends {
my $recommends = OPTIONAL_MODULES();
my @blacklist = ('Apache-SizeLimit', 'mod_perl'); # Does not compile properly on Travis
my $hrecommends = {};
foreach my $module (@$recommends) {
next if grep($_ eq $module->{package}, @blacklist);
$hrecommends->{$module->{module}} = $module->{version};
}
return $hrecommends;
}
my $build = Module::Build->new(
module_name => 'Bugzilla',
dist_abstract => <<END,
Bugzilla is a free bug-tracking system that is developed by an active
community of volunteers. You can install and use it without having to
pay any license fee.
END
dist_version_from => 'Bugzilla/Constants.pm',
dist_version => BUGZILLA_VERSION,
requires => requires(),
recommends => recommends(),
license => 'Mozilla_2_0',
create_readme => 0,
create_makefile_pl => 0
);
$build->create_build_script;
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
#!start included /usr/share/perl5/ExtUtils/MANIFEST.SKIP
# Avoid version control files.
\B\.git\b
\B\.bzr\b
\B\.bzrignore\b
\B\.gitignore\b
\B\.gitrev\b
\B\.patch\b
# Avoid Makemaker generated and utility files.
\bMANIFEST\.bak
\bMakefile$
\bblib/
\bMakeMaker-\d
\bpm_to_blib\.ts$
\bpm_to_blib$
\bblibdirs\.ts$ # 6.18 through 6.25 generated this
# Avoid Module::Build generated and utility files.
\bBuild$
\b_build/
# Avoid temp and backup files.
~$
\.old$
\#$
\b\.#
\.bak$
\.swp$
#!end included /usr/share/perl5/ExtUtils/MANIFEST.SKIP
# Avoid Module::Build generated and utility files.
\bBuild$
\bBuild.bat$
\b_build
\bBuild.COM$
\bBUILD.COM$
\bbuild.com$
# Avoid archives of this distribution
\bBugzilla-[\d\.\_]+
# Bugzilla specific avoids
\bdata\/\b
\blocalconfig$
......@@ -24,7 +24,6 @@ use Getopt::Long;
use Pod::Usage;
use File::Basename qw(dirname);
use File::Spec;
use HTTP::Cookies;
use XMLRPC::Lite;
# If you want, say “use Bugzilla::WebService::Constants” here to get access
......@@ -36,7 +35,8 @@ my $help;
my $Bugzilla_uri;
my $Bugzilla_login;
my $Bugzilla_password;
my $Bugzilla_remember;
my $Bugzilla_restrict;
my $Bugzilla_token;
my $bug_id;
my $product_name;
my $create_file_name;
......@@ -51,7 +51,7 @@ GetOptions('help|h|?' => \$help,
'uri=s' => \$Bugzilla_uri,
'login:s' => \$Bugzilla_login,
'password=s' => \$Bugzilla_password,
'rememberlogin!' => \$Bugzilla_remember,
'restrictlogin!' => \$Bugzilla_restrict,
'bug_id:s' => \$bug_id,
'product_name:s' => \$product_name,
'create:s' => \$create_file_name,
......@@ -86,14 +86,14 @@ Specify this without a value in order to log out.
Bugzilla password. Specify this together with B<--login> in order to log in.
=item --rememberlogin
=item --restrictlogin
Gives access to Bugzilla's "Bugzilla_remember" option.
Specify this option while logging in to do the same thing as ticking the
C<Bugzilla_remember> box on Bugilla's log in form.
Gives access to Bugzilla's "Bugzilla_restrictlogin" option.
Specify this option while logging in to restrict the login token to be
only valid from the IP address which called
Don't specify this option to do the same thing as unchecking the box.
See Bugzilla's rememberlogin parameter for details.
See Bugzilla's restrictlogin parameter for details.
=item --bug_id
......@@ -151,17 +151,6 @@ my $soapresult;
# We will use this variable for function call results.
my $result;
# Open our cookie jar. We save it into a file so that we may re-use cookies
# to avoid the need of logging in every time. You're encouraged, but not
# required, to do this in your applications, too.
# Cookies are only saved if Bugzilla's rememberlogin parameter is set to one of
# - on
# - defaulton (and you didn't pass 0 as third parameter to User.login)
# - defaultoff (and you passed 1 as third parameter to User.login)
my $cookie_jar =
new HTTP::Cookies('file' => File::Spec->catdir(dirname($0), 'cookies.txt'),
'autosave' => 1);
=head2 Initialization
Using the XMLRPC::Lite class, you set up a proxy, as shown in this script.
......@@ -170,8 +159,7 @@ of C<http://your.bugzilla.installation/path/to/bugzilla/xmlrpc.cgi>.
=cut
my $proxy = XMLRPC::Lite->proxy($Bugzilla_uri,
'cookie_jar' => $cookie_jar);
my $proxy = XMLRPC::Lite->proxy($Bugzilla_uri);
=head2 Debugging
......@@ -205,25 +193,6 @@ $soapresult = $proxy->call('Bugzilla.timezone');
_die_on_fault($soapresult);
print 'Bugzilla\'s timezone is ' . $soapresult->result()->{timezone} . ".\n";
=head2 Getting Extension Information
Returns all the information any extensions have decided to provide to the webservice.
=cut
if ($fetch_extension_info) {
$soapresult = $proxy->call('Bugzilla.extensions');
_die_on_fault($soapresult);
my $extensions = $soapresult->result()->{extensions};
foreach my $extensionname (keys(%$extensions)) {
print "Extension '$extensionname' information\n";
my $extension = $extensions->{$extensionname};
foreach my $data (keys(%$extension)) {
print ' ' . $data . ' => ' . $extension->{$data} . "\n";
}
}
}
=head2 Logging In and Out
=head3 Using Bugzilla's Environment Authentication
......@@ -238,21 +207,20 @@ You don't log out if you're using this kind of authentication.
Use the C<User.login> and C<User.logout> calls to log in and out, as shown
in this script.
The C<Bugzilla_remember> parameter is optional.
If omitted, Bugzilla's defaults apply (as specified by its C<rememberlogin>
The C<Bugzilla_restrictlogin> parameter is optional.
If omitted, Bugzilla's defaults apply (as specified by its C<restrictlogin>
parameter).
Bugzilla hands back cookies you'll need to pass along during your work calls.
=cut
if (defined($Bugzilla_login)) {
if ($Bugzilla_login ne '') {
# Log in.
$soapresult = $proxy->call('User.login',
{ login => $Bugzilla_login,
{ login => $Bugzilla_login,
password => $Bugzilla_password,
remember => $Bugzilla_remember } );
restrict_login => $Bugzilla_restrict } );
$Bugzilla_token = $soapresult->result->{token};
_die_on_fault($soapresult);
print "Login successful.\n";
}
......@@ -264,17 +232,36 @@ if (defined($Bugzilla_login)) {
}
}
=head2 Getting Extension Information
Returns all the information any extensions have decided to provide to the webservice.
=cut
if ($fetch_extension_info) {
$soapresult = $proxy->call('Bugzilla.extensions', {token => $Bugzilla_token});
_die_on_fault($soapresult);
my $extensions = $soapresult->result()->{extensions};
foreach my $extensionname (keys(%$extensions)) {
print "Extension '$extensionname' information\n";
my $extension = $extensions->{$extensionname};
foreach my $data (keys(%$extension)) {
print ' ' . $data . ' => ' . $extension->{$data} . "\n";
}
}
}
=head2 Retrieving Bug Information
Call C<Bug.get> with the ID of the bug you want to know more of.
The call will return a C<Bugzilla::Bug> object.
The call will return a C<Bugzilla::Bug> object.
Note: You can also use "Bug.get_bugs" for compatibility with Bugzilla 3.0 API.
=cut
if ($bug_id) {