diff options
Diffstat (limited to 'contrib/modules/m_bugzilla.sh')
-rw-r--r-- | contrib/modules/m_bugzilla.sh | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/contrib/modules/m_bugzilla.sh b/contrib/modules/m_bugzilla.sh new file mode 100644 index 0000000..c428cdc --- /dev/null +++ b/contrib/modules/m_bugzilla.sh @@ -0,0 +1,231 @@ +#!/bin/bash +# -*- coding: utf-8 -*- +########################################################################### +# # +# envbot - an IRC bot in bash # +# Copyright (C) 2007-2008 Arvid Norlander # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <http://www.gnu.org/licenses/>. # +# # +########################################################################### +#--------------------------------------------------------------------- +## Check bugs using the program bugz and return output from it. +## @pybugz bugz is a tool to search Gentoo bug reports (or other bugzillas)<br /> +## @pybugz From eix pybugz:<br /> +## @pybugz Description: Command line interface to (Gentoo) Bugzilla +## @Dependencies This module therefore depends on:<br /> +## @Dependencies pybugz +## @Config_variables To set bugzilla to use something like this in config:<br /> +## @Config_variables <pre>config_module_bugzilla_tracker_name[0]='gentoo' +## @Config_variables config_module_bugzilla_tracker_url[0]='https://bugs.gentoo.org/'</pre> +## @Config_variables Must end in trailing slash! Also the first entry will be the default.<br /> +## @Config_variables You also need to specify flood limiting<br /> +## @Config_variables (how often in seconds)<br /> +## @Config_variables <tt>config_module_bugzilla_rate='10'</tt> +#--------------------------------------------------------------------- + +module_bugzilla_INIT() { + modinit_API='2' + modinit_HOOKS='after_load' + commands_register "$1" 'bugs_search' 'bugs search' || return 1 + commands_register "$1" 'bug' || return 1 + helpentry_module_bugzilla_description="Search in bugzilla bug trackers." + + helpentry_bugzilla_bugs_search_syntax='[-t <tracker>] [-(all|closed)] <pattern>' + helpentry_bugzilla_bugs_search_description='Search for <pattern> in <tracker> (or the default tracker).' + + helpentry_bugzilla_bug_syntax='[-t <tracker>] <id>' + helpentry_bugzilla_bug_description='Look up the bug with <id> in <tracker> (or the default tracker).' +} + +module_bugzilla_UNLOAD() { + unset module_bugzilla_last_query module_bugzilla_default_bugtracker + unset module_bugzilla_parse_config module_bugzilla_find_tracker + hash_reset 'bugzilla_tracker' +} + +module_bugzilla_REHASH() { + module_bugzilla_parse_config +} + +#--------------------------------------------------------------------- +## Initialize the hash of name -> url mapping +## @Type Private +#--------------------------------------------------------------------- +module_bugzilla_parse_config() { + hash_reset 'bugzilla_tracker' + local index + for index in "${!config_module_bugzilla_tracker_name[@]}"; do + hash_set 'bugzilla_tracker' \ + "${config_module_bugzilla_tracker_name[index]}" \ + "${config_module_bugzilla_tracker_url[index]}" + done + module_bugzilla_default_bugtracker="${config_module_bugzilla_tracker_url[0]}" +} + +#--------------------------------------------------------------------- +## Find what tracker to use from the parameters. +## @param Name of parameter variable. +## @param Name of bugtracker variable. +## @Type Private +#--------------------------------------------------------------------- +module_bugzilla_find_tracker() { + if [[ "${!1}" =~ ^(-(tracker|t)\ +([A-Za-z0-9]+)\ +)(.+) ]]; then + local tindex="${BASH_REMATCH[3]}" + # Store result back in variable. + printf -v "$1" '%s' "${BASH_REMATCH[4]}" + local turl + hash_get 'bugzilla_tracker' "$tindex" 'turl' + if [[ $turl ]]; then + printf -v "$2" '%s' "$turl" + else + feedback_generic_error "$sendernick" "bugs search" "No such bug tracker found." + fi + else + printf -v "$2" '%s' "${module_bugzilla_default_bugtracker}" + fi +} + +# Called after module has loaded. +# Check for bugz +module_bugzilla_after_load() { + if ! hash bugz > /dev/null 2>&1; then + log_error "Couldn't find bugz command line tool. The bugzilla module depend on that tool (emerge pybugz to get it on Gentoo)." + return 1 + fi + if [[ -z ${config_module_bugzilla_tracker_url[0]} ]]; then + log_error "Please set at least config_module_bugzilla_url[0] in config." + return 1 + fi + if [[ -z ${config_module_bugzilla_tracker_name[0]} ]]; then + log_error "Please set at least config_module_bugzilla_name[0] in config." + return 1 + fi + if [[ -z $config_module_bugzilla_rate ]]; then + log_error "Please set config_module_bugzilla_rate in config." + return 1 + fi + module_bugzilla_parse_config + unset module_bugzilla_last_query + module_bugzilla_last_query='0' +} + +module_bugzilla_handler_bugs_search() { + # Accept this anywhere, unless someone can give a good reason not to. + local sender="$1" + local channel="$2" + local sendernick= + parse_hostmask_nick "$sender" 'sendernick' + # If it isn't in a channel send message back to person who send it, + # otherwise send in channel + if ! [[ $2 =~ ^# ]]; then + channel="$sendernick" + fi + local parameters="$3" + local bugtracker + module_bugzilla_find_tracker 'parameters' 'bugtracker' + if [[ "$parameters" =~ ^(-(all|closed)\ +)?(.+) ]]; then + local mode="${BASH_REMATCH[2]}" + local pattern="${BASH_REMATCH[@]: -1}" + # Simple flood limiting + if time_check_interval "$module_bugzilla_last_query" "$config_module_bugzilla_rate"; then + time_get_current 'module_bugzilla_last_query' + local bugs_parameters="" + if [[ $mode = "all" ]]; then + bugs_parameters="-s all" + elif [[ $mode = "closed" ]]; then + bugs_parameters="-s CLOSED -s RESOLVED" + fi + log_info_file bugzilla.log "$sender made the bot run pybugz search on \"$pattern\"" + # We unset TERM because otherwise bugz output some control codes + local result="$(unset TERM; ulimit -t 4; bugz -fqb "$bugtracker" search $bugs_parameters "$pattern")" + local lines="$(wc -l <<< "$result")" + local header footer + # Some odd formatting chars are always returned (in some versions of pybugz), so we can't check for empty string. + if [[ ${#result} -le 10 ]]; then + header="No bugs matching \"$pattern\" found" + elif [[ $lines -gt 1 ]]; then + header="First bug matching \"$pattern\": " + footer=" ($lines more bugs found)" + else + header="One bug matching \"$pattern\" found: " + fi + if [[ $(head -n 1 <<< "$result") =~ \ ([0-9]+)\ +([^ ]+)\ +(.*)$ ]]; then + local pretty_result="${format_bold}${bugtracker}${BASH_REMATCH[1]}${format_bold} ${format_bold}Description${format_bold}: ${BASH_REMATCH[3]} ${format_bold}Assigned To${format_bold}: ${BASH_REMATCH[2]}" + fi + send_msg "$channel" "${header}${pretty_result}${footer}" + else + log_error_file bugzilla.log "FLOOD DETECTED in bugzilla module" + fi + else + feedback_bad_syntax "$sendernick" "bugs search" "[-t tracker] [-(all|closed)] <pattern>" + fi +} + +module_bugzilla_handler_bug() { + # Accept this anywhere, unless someone can give a good reason not to. + local sender="$1" + local channel="$2" + local sendernick= + parse_hostmask_nick "$sender" 'sendernick' + # If it isn't in a channel send message back to person who send it, + # otherwise send in channel + if ! [[ $2 =~ ^# ]]; then + channel="$sendernick" + fi + local parameters="$3" + local bugtracker + module_bugzilla_find_tracker 'parameters' 'bugtracker' + # Extract bug ID + if [[ "$parameters" =~ ^([0-9]+) ]]; then + local id="${BASH_REMATCH[1]}" + # Simple flood limiting + if time_check_interval "$module_bugzilla_last_query" "$config_module_bugzilla_rate"; then + time_get_current 'module_bugzilla_last_query' + log_info_file bugzilla.log "$sender made the bot check with pybugz for bug \"$id\"" + # We unset TERM because otherwise bugz output some control codes + local result="$(unset TERM; ulimit -t 4; bugz -fqb "$bugtracker" get -n "$id" | grep -E 'Title|Status|Resolution')" + local resultread pretty_result + local title status resolution + # Read the data out of the multiline result. + while read -r resultread; do + if [[ $resultread =~ ^Title[\ :]+([^ ].*) ]]; then + title="${BASH_REMATCH[1]}" + elif [[ $resultread =~ ^Status[\ :]+([^ ].*) ]]; then + status="${BASH_REMATCH[1]}" + elif [[ $resultread =~ ^Resolution[\ :]+([^ ].*) ]]; then + resolution="${BASH_REMATCH[1]}" + fi + done <<< "$result" + # Yes this is a bit of a mess + if [[ "$title" ]]; then + # This info is always here + pretty_result="${format_bold}Bug $id${format_bold} (${format_bold}Status${format_bold} $status" + # The resolution may not exist, add it if it does. + if [[ $resolution ]]; then + pretty_result+=", ${format_bold}Resolution${format_bold} $resolution" + fi + # And add the title in. Does not depend on if resolution exist. + pretty_result+="): $title (${bugtracker}${id})" + else + pretty_result="Bug $id not found" + fi + send_msg "$channel" "${pretty_result}" + else + log_error_file bugzilla.log "FLOOD DETECTED in bugzilla module" + fi + else + feedback_bad_syntax "$sendernick" "bug" "[-t tracker] <id>" + fi +} |