From e02bf3c9a4b6b6265beaf998376daed250a3bfdb Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Fri, 3 Jul 2026 14:31:01 +0100 Subject: [PATCH] Bug 1917419: Port the MoreBugUrl extension from upstream Bugzilla Restores the bug_url_sub_classes hook (previously dropped in Harmony) and ports the MoreBugUrl extension from upstream, adding recognition of additional external bug trackers in the See Also field: BitBucket, ReviewBoard, RT, PHP, Redmine, Savane and WineHQ Forums. Bugzilla::BugUrl::class_for now fires the bug_url_sub_classes hook so extensions can append their own Bugzilla::BugUrl sub-classes. Core trackers are still tried first; extension-provided trackers are appended last. Bugzilla/Hook.pm documents the hook, matching upstream. The upstream extension's Rietveld and GetSatisfaction trackers are omitted as both services are defunct. The extension modules are adapted to Harmony conventions (use 5.10.1) and the extension ships enabled (no "disabled" marker). --- Bugzilla/BugUrl.pm | 7 ++- Bugzilla/Hook.pm | 15 ++++++ extensions/MoreBugUrl/Config.pm | 20 ++++++++ extensions/MoreBugUrl/Extension.pm | 50 +++++++++++++++++++ extensions/MoreBugUrl/lib/BitBucket.pm | 40 +++++++++++++++ extensions/MoreBugUrl/lib/PHP.pm | 44 ++++++++++++++++ extensions/MoreBugUrl/lib/RT.pm | 42 ++++++++++++++++ extensions/MoreBugUrl/lib/Redmine.pm | 42 ++++++++++++++++ extensions/MoreBugUrl/lib/ReviewBoard.pm | 47 +++++++++++++++++ extensions/MoreBugUrl/lib/Savane.pm | 40 +++++++++++++++ extensions/MoreBugUrl/lib/WineHQForums.pm | 46 +++++++++++++++++ ...er-error-bug_url_invalid_tracker.html.tmpl | 15 ++++++ 12 files changed, 407 insertions(+), 1 deletion(-) create mode 100644 extensions/MoreBugUrl/Config.pm create mode 100644 extensions/MoreBugUrl/Extension.pm create mode 100644 extensions/MoreBugUrl/lib/BitBucket.pm create mode 100644 extensions/MoreBugUrl/lib/PHP.pm create mode 100644 extensions/MoreBugUrl/lib/RT.pm create mode 100644 extensions/MoreBugUrl/lib/Redmine.pm create mode 100644 extensions/MoreBugUrl/lib/ReviewBoard.pm create mode 100644 extensions/MoreBugUrl/lib/Savane.pm create mode 100644 extensions/MoreBugUrl/lib/WineHQForums.pm create mode 100644 extensions/MoreBugUrl/template/en/default/hook/global/user-error-bug_url_invalid_tracker.html.tmpl diff --git a/Bugzilla/BugUrl.pm b/Bugzilla/BugUrl.pm index dd0c0a5823..1b679bb2c0 100644 --- a/Bugzilla/BugUrl.pm +++ b/Bugzilla/BugUrl.pm @@ -16,6 +16,7 @@ use base qw(Bugzilla::Object); use Bugzilla::Util; use Bugzilla::Error; use Bugzilla::Constants; +use Bugzilla::Hook; use Module::Runtime qw(require_module); use URI::QueryParam; @@ -131,8 +132,12 @@ sub should_handle { sub class_for { my ($class, $value) = @_; + my @sub_classes = $class->SUB_CLASSES; + Bugzilla::Hook::process('bug_url_sub_classes', + {sub_classes => \@sub_classes}); + my $uri = URI->new($value); - foreach my $subclass ($class->SUB_CLASSES) { + foreach my $subclass (@sub_classes) { require_module($subclass); return wantarray ? ($subclass, $uri) : $subclass if $subclass->should_handle($uri); diff --git a/Bugzilla/Hook.pm b/Bugzilla/Hook.pm index 07ef07fde8..57b22dcbf7 100644 --- a/Bugzilla/Hook.pm +++ b/Bugzilla/Hook.pm @@ -533,6 +533,21 @@ The hash of changed fields. C<< $changes->{field} = [old, new] >> =back +=head2 bug_url_sub_classes + +Allows you to add more L sub-classes. + +See the C extension to see how things work. + +Params: + +=over + +=item C - An arrayref of strings which represent L +sub-classes. + +=back + =head2 buglist_columns This happens in L, which determines legal bug diff --git a/extensions/MoreBugUrl/Config.pm b/extensions/MoreBugUrl/Config.pm new file mode 100644 index 0000000000..f8175bb4cf --- /dev/null +++ b/extensions/MoreBugUrl/Config.pm @@ -0,0 +1,20 @@ +# 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. + +package Bugzilla::Extension::MoreBugUrl; + +use 5.10.1; +use strict; +use warnings; + +use constant NAME => 'MoreBugUrl'; + +use constant REQUIRED_MODULES => []; + +use constant OPTIONAL_MODULES => []; + +__PACKAGE__->NAME; diff --git a/extensions/MoreBugUrl/Extension.pm b/extensions/MoreBugUrl/Extension.pm new file mode 100644 index 0000000000..c555423593 --- /dev/null +++ b/extensions/MoreBugUrl/Extension.pm @@ -0,0 +1,50 @@ +# 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. + +package Bugzilla::Extension::MoreBugUrl; + +use 5.10.1; +use strict; +use warnings; + +use base qw(Bugzilla::Extension); + +use constant MORE_SUB_CLASSES => qw( + Bugzilla::Extension::MoreBugUrl::BitBucket + Bugzilla::Extension::MoreBugUrl::ReviewBoard + Bugzilla::Extension::MoreBugUrl::RT + Bugzilla::Extension::MoreBugUrl::PHP + Bugzilla::Extension::MoreBugUrl::Redmine + Bugzilla::Extension::MoreBugUrl::Savane + Bugzilla::Extension::MoreBugUrl::WineHQForums +); + +# We need to update the bug_see_also table because ReviewBoard was +# originally under Bugzilla/BugUrl/. +sub install_update_db { + my $dbh = Bugzilla->dbh; + + my $should_rename = $dbh->selectrow_array(q{SELECT 1 FROM bug_see_also + WHERE class = 'Bugzilla::BugUrl::ReviewBoard'} + ); + + if ($should_rename) { + my $sth = $dbh->prepare( + 'UPDATE bug_see_also SET class = ? + WHERE class = ?' + ); + $sth->execute('Bugzilla::Extension::MoreBugUrl::ReviewBoard', + 'Bugzilla::BugUrl::ReviewBoard'); + } +} + +sub bug_url_sub_classes { + my ($self, $args) = @_; + push @{$args->{sub_classes}}, MORE_SUB_CLASSES; +} + +__PACKAGE__->NAME; diff --git a/extensions/MoreBugUrl/lib/BitBucket.pm b/extensions/MoreBugUrl/lib/BitBucket.pm new file mode 100644 index 0000000000..bc9f277408 --- /dev/null +++ b/extensions/MoreBugUrl/lib/BitBucket.pm @@ -0,0 +1,40 @@ +# 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. + +package Bugzilla::Extension::MoreBugUrl::BitBucket; + +use 5.10.1; +use strict; +use warnings; + +use base qw(Bugzilla::BugUrl); + +############################### +#### Methods #### +############################### + +sub should_handle { + my ($class, $uri) = @_; + + # BitBucket issues have the form of + # bitbucket.org/user/project/issue/1234 + return (lc($uri->authority) eq "bitbucket.org" + && $uri->path =~ m|[^/]+/[^/]+/issue/\d+|i) ? 1 : 0; +} + +sub _check_value { + my $class = shift; + + my $uri = $class->SUPER::_check_value(@_); + + my ($path) = $uri->path =~ m|([^/]+/[^/]+/issue/\d+)|i; + $uri = new URI("https://bitbucket.org/$path"); + + return $uri; +} + +1; diff --git a/extensions/MoreBugUrl/lib/PHP.pm b/extensions/MoreBugUrl/lib/PHP.pm new file mode 100644 index 0000000000..29fcc662f5 --- /dev/null +++ b/extensions/MoreBugUrl/lib/PHP.pm @@ -0,0 +1,44 @@ +# 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. + +package Bugzilla::Extension::MoreBugUrl::PHP; + +use 5.10.1; +use strict; +use warnings; + +use base qw(Bugzilla::BugUrl); + +############################### +#### Methods #### +############################### + +sub should_handle { + my ($class, $uri) = @_; + + # PHP Bug URLs have only one form: + # https://bugs.php.net/bug.php?id=1234 + return (lc($uri->authority) eq 'bugs.php.net' + and $uri->path =~ m|/bug\.php$| + and $uri->query_param('id') =~ /^\d+$/) ? 1 : 0; +} + +sub _check_value { + my $class = shift; + + my $uri = $class->SUPER::_check_value(@_); + + # PHP Bug URLs redirect to HTTPS, so just use the HTTPS scheme. + $uri->scheme('https'); + + # And remove any # part if there is one. + $uri->fragment(undef); + + return $uri; +} + +1; diff --git a/extensions/MoreBugUrl/lib/RT.pm b/extensions/MoreBugUrl/lib/RT.pm new file mode 100644 index 0000000000..52aab48d1f --- /dev/null +++ b/extensions/MoreBugUrl/lib/RT.pm @@ -0,0 +1,42 @@ +# 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. + +package Bugzilla::Extension::MoreBugUrl::RT; + +use 5.10.1; +use strict; +use warnings; + +use base qw(Bugzilla::BugUrl); + +############################### +#### Methods #### +############################### + +sub should_handle { + my ($class, $uri) = @_; + + # RT URLs can look like various things: + # http://example.com/rt/Ticket/Display.html?id=1234 + # https://example.com/Public/Bug/Display.html?id=1234 + return ($uri->path =~ m|/Display\.html$| and $uri->query_param('id') =~ /^\d+$/) + ? 1 + : 0; +} + +sub _check_value { + my $class = shift; + + my $uri = $class->SUPER::_check_value(@_); + + # And remove any # part if there is one. + $uri->fragment(undef); + + return $uri; +} + +1; diff --git a/extensions/MoreBugUrl/lib/Redmine.pm b/extensions/MoreBugUrl/lib/Redmine.pm new file mode 100644 index 0000000000..577d08bbb2 --- /dev/null +++ b/extensions/MoreBugUrl/lib/Redmine.pm @@ -0,0 +1,42 @@ +# 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. + +package Bugzilla::Extension::MoreBugUrl::Redmine; + +use 5.10.1; +use strict; +use warnings; + +use base qw(Bugzilla::BugUrl); + +############################### +#### Methods #### +############################### + +sub should_handle { + my ($class, $uri) = @_; + return ($uri->path =~ m|/issues/\d+$|) ? 1 : 0; +} + +sub _check_value { + my $class = shift; + + my $uri = $class->SUPER::_check_value(@_); + + # Redmine URLs have only one form: + # http://demo.redmine.com/issues/111 + + # Make sure there are no query parameters. + $uri->query(undef); + + # And remove any # part if there is one. + $uri->fragment(undef); + + return $uri; +} + +1; diff --git a/extensions/MoreBugUrl/lib/ReviewBoard.pm b/extensions/MoreBugUrl/lib/ReviewBoard.pm new file mode 100644 index 0000000000..49c904523e --- /dev/null +++ b/extensions/MoreBugUrl/lib/ReviewBoard.pm @@ -0,0 +1,47 @@ +# 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. + +package Bugzilla::Extension::MoreBugUrl::ReviewBoard; + +use 5.10.1; +use strict; +use warnings; + +use base qw(Bugzilla::BugUrl); + +############################### +#### Methods #### +############################### + +sub should_handle { + my ($class, $uri) = @_; + return ($uri->path =~ m|/r/\d+/?$|) ? 1 : 0; +} + +sub _check_value { + my $class = shift; + + my $uri = $class->SUPER::_check_value(@_); + + # Review Board URLs have only one form (the trailing slash is optional): + # http://reviews.reviewboard.org/r/111/ + + # Make sure there are no query parameters. + $uri->query(undef); + + # And remove any # part if there is one. + $uri->fragment(undef); + + # make sure the trailing slash is present + if ($uri->path !~ m|/$|) { + $uri->path($uri->path . '/'); + } + + return $uri; +} + +1; diff --git a/extensions/MoreBugUrl/lib/Savane.pm b/extensions/MoreBugUrl/lib/Savane.pm new file mode 100644 index 0000000000..a0ea2f825a --- /dev/null +++ b/extensions/MoreBugUrl/lib/Savane.pm @@ -0,0 +1,40 @@ +# 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. + +package Bugzilla::Extension::MoreBugUrl::Savane; + +use 5.10.1; +use strict; +use warnings; + +use base qw(Bugzilla::BugUrl); + +############################### +#### Methods #### +############################### + +sub should_handle { + my ($class, $uri) = @_; + return ($uri->as_string =~ m|/bugs/(index\.php)?\?\d+$|) ? 1 : 0; +} + +sub _check_value { + my $class = shift; + + my $uri = $class->SUPER::_check_value(@_); + + # Savane URLs have only two forms: + # http://gna.org/bugs/index.php?12345 + # http://gna.org/bugs/?12345 + + # And remove any # part if there is one. + $uri->fragment(undef); + + return $uri; +} + +1; diff --git a/extensions/MoreBugUrl/lib/WineHQForums.pm b/extensions/MoreBugUrl/lib/WineHQForums.pm new file mode 100644 index 0000000000..274f9e9cf0 --- /dev/null +++ b/extensions/MoreBugUrl/lib/WineHQForums.pm @@ -0,0 +1,46 @@ +# 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. + +package Bugzilla::Extension::MoreBugUrl::WineHQForums; + +use 5.10.1; +use strict; +use warnings; + +use base qw(Bugzilla::BugUrl); + +############################### +#### Methods #### +############################### + +sub should_handle { + my ($class, $uri) = @_; + + # WineHQ Forums URLs only have one form: + # http(s)://forum.winehq.org/viewtopic.php?f=1234&t=1234 + return (lc($uri->authority) eq 'forum.winehq.org' + and $uri->path =~ m|^/viewtopic\.php$| + and $uri->query_param('f') =~ /^\d+$/ + and $uri->query_param('t') =~ /^\d+$/) ? 1 : 0; +} + +sub _check_value { + my $class = shift; + + my $uri = $class->SUPER::_check_value(@_); + + # WineHQ Forums HTTP URLs redirect to HTTPS, so just use the HTTPS + # scheme. + $uri->scheme('https'); + + # Remove any # part if there is one. + $uri->fragment(undef); + + return $uri; +} + +1; diff --git a/extensions/MoreBugUrl/template/en/default/hook/global/user-error-bug_url_invalid_tracker.html.tmpl b/extensions/MoreBugUrl/template/en/default/hook/global/user-error-bug_url_invalid_tracker.html.tmpl new file mode 100644 index 0000000000..21b25cdcfa --- /dev/null +++ b/extensions/MoreBugUrl/template/en/default/hook/global/user-error-bug_url_invalid_tracker.html.tmpl @@ -0,0 +1,15 @@ +[%# 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. + #%] + +
  • An issue on bitbucket.org.
  • +
  • A Review Board review request.
  • +
  • A ticket in an RT installation.
  • +
  • A b[% %]ug on b[% %]ugs.php.net.
  • +
  • An issue in a Redmine installation.
  • +
  • A b[% %]ug in a Savane installation.
  • +
  • A b[% %]ug related topic on WineHQ forums