6.3. The Bugzilla Extension Mechanism


Note that the below paths are inconsistent and confusing. They will likely be changed in Bugzilla 4.0.

Extensions are a way for extensions to Bugzilla to insert code into the standard Bugzilla templates and source files without modifying these files themselves. The extension mechanism defines a consistent API for extending the standard templates and source files in a way that cleanly separates standard code from extension code. Hooks reduce merge conflicts and make it easier to write extensions that work across multiple versions of Bugzilla, making upgrading a Bugzilla installation with installed extensions easier. Furthermore, they make it easy to install and remove extensions as each extension is nothing more than a simple directory structure.

There are two main types of hooks: code hooks and template hooks. Code hooks allow extensions to invoke code at specific points in various source files, while template hooks allow extensions to add elements to the Bugzilla user interface.

A hook is just a named place in a standard source or template file where extension source code or template files for that hook get processed. Each extension has a corresponding directory in the Bugzilla directory tree (BUGZILLA_ROOT/extensions/extension_name). Hooking an extension source file or template to a hook is as simple as putting the extension file into extension's template or code directory. When Bugzilla processes the source file or template and reaches the hook, it will process all extension files in the hook's directory. The hooks themselves can be added into any source file or standard template upon request by extension authors.

To use hooks to extend Bugzilla, first make sure there is a hook at the appropriate place within the source file or template you want to extend. The exact appearance of a hook depends on if the hook is a code hook or a template hook.

Code hooks appear in Bugzilla source files as a single method call in the format Bugzilla::Hook->process("name");. For instance, enter_bug.cgi may invoke the hook "enter_bug-entrydefaultvars". Thus, a source file at BUGZILLA_ROOT/extensions/EXTENSION_NAME/code/enter_bug-entrydefaultvars.pl will be automatically invoked when the code hook is reached.

Template hooks appear in the standard Bugzilla templates as a single directive in the format [% Hook.process("name") %], where name is the unique name of the hook.

If you aren't sure what you want to extend or just want to browse the available hooks, either use your favorite multi-file search tool (e.g. grep) to search the standard templates for occurrences of Hook.process or the source files for occurrences of Bugzilla::Hook::process.

If there is no hook at the appropriate place within the Bugzilla source file or template you want to extend, file a bug requesting one, specifying:

the source or template file for which you are requesting a hook;
where in the file you would like the hook to be placed (line number/position for latest version of the file in CVS or description of location);
the purpose of the hook;
a link to information about your extension, if any.

The Bugzilla reviewers will promptly review each hook request, name the hook, add it to the template or source file, and check the new version of the template into CVS.

You may optionally attach a patch to the bug which implements the hook and check it in yourself after receiving approval from a Bugzilla reviewer. The developers may suggest changes to the location of the hook based on their analysis of your needs or so the hook can satisfy the needs of multiple extensions, but the process of getting hooks approved and checked in is not as stringent as the process for general changes to Bugzilla, and any extension, whether released or still in development, can have hooks added to meet their needs.

After making sure the hook you need exists (or getting it added if not), add your extension to the directory within the Bugzilla extensions tree corresponding to the hook.

That's it! Now, when the source file or template containing the hook is processed, your extension file will be processed at the point where the hook appears.

For example, let's say you have an extension named Projman that adds project management capabilities to Bugzilla. Projman has an administration interface edit-projects.cgi, and you want to add a link to it into the navigation bar at the bottom of every Bugzilla page for those users who are authorized to administer projects.

The navigation bar is generated by the template file useful-links.html.tmpl, which is located in the global/ subdirectory on the standard Bugzilla template path BUGZILLA_ROOT/template/en/default/. Looking in useful-links.html.tmpl, you find the following hook at the end of the list of standard Bugzilla administration links:

    [% ', <a href="editkeywords.cgi">keywords</a>' 
       IF user.in_group('editkeywords') %]
    [% Hook.process("edit") %]

The corresponding extension file for this hook is BUGZILLA_ROOT/extensions/projman/template/en/global/useful-links-edit.html.tmpl. You then create that template file and add the following constant:

...[% ', <a href="edit-projects.cgi">projects</a>' IF user.in_group('projman_admins') %]

Voila! The link now appears after the other administration links in the navigation bar for users in the projman_admins group.

Now, let us say your extension adds a custom "project_manager" field to enter_bug.cgi. You want to modify the CGI script to set the default project manager to be productname@company.com. Looking at enter_bug.cgi, you see the enter_bug-entrydefaultvars hook near the bottom of the file before the default form values are set. The corresponding extension source file for this hook is located at BUGZILLA_ROOT/extensions/projman/code/enter_bug-entrydefaultvars.pl. You then create that file and add the following:

$default{'project_manager'} = $product.'@company.com';

This code will be invoked whenever enter_bug.cgi is executed. Assuming that the rest of the customization was completed (e.g. the custom field was added to the enter_bug template and the required hooks were used in process_bug.cgi), the new field will now have this default value.