You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2659 lines
92 KiB
2659 lines
92 KiB
5 years ago
|
From 611ca48b8d81e5edc0907885ece48cb0dce986fa Mon Sep 17 00:00:00 2001
|
||
|
From: Matej Habrnal <mhabrnal@redhat.com>
|
||
|
Date: Tue, 13 Jan 2015 19:30:27 -0500
|
||
|
Subject: [PATCH] reporter-mantisbt: first version of the reporter-mantisbt
|
||
|
|
||
|
Related to #272
|
||
|
|
||
|
Signed-off-by: Matej Habrnal <mhabrnal@redhat.com>
|
||
|
---
|
||
|
configure.ac | 33 +
|
||
|
po/POTFILES.in | 11 +
|
||
|
src/plugins/Makefile.am | 43 +-
|
||
|
src/plugins/centos_report_event.conf | 37 +
|
||
|
src/plugins/mantisbt.c | 1111 ++++++++++++++++++++++++
|
||
|
src/plugins/mantisbt.conf | 8 +
|
||
|
src/plugins/mantisbt.h | 140 +++
|
||
|
src/plugins/mantisbt_format.conf | 59 ++
|
||
|
src/plugins/mantisbt_formatdup.conf | 65 ++
|
||
|
src/plugins/report_CentOSBugTracker.conf | 4 +
|
||
|
src/plugins/report_CentOSBugTracker.xml.in | 65 ++
|
||
|
src/plugins/reporter-mantisbt.c | 696 +++++++++++++++
|
||
|
src/workflows/Makefile.am | 15 +-
|
||
|
src/workflows/report_centos.conf | 31 +
|
||
|
src/workflows/workflow_CentOSCCpp.xml.in | 12 +
|
||
|
src/workflows/workflow_CentOSJava.xml.in | 11 +
|
||
|
src/workflows/workflow_CentOSKerneloops.xml.in | 11 +
|
||
|
src/workflows/workflow_CentOSLibreport.xml.in | 9 +
|
||
|
src/workflows/workflow_CentOSPython.xml.in | 11 +
|
||
|
src/workflows/workflow_CentOSPython3.xml.in | 11 +
|
||
|
src/workflows/workflow_CentOSVmcore.xml.in | 12 +
|
||
|
src/workflows/workflow_CentOSXorg.xml.in | 9 +
|
||
|
22 files changed, 2402 insertions(+), 2 deletions(-)
|
||
|
create mode 100644 src/plugins/centos_report_event.conf
|
||
|
create mode 100644 src/plugins/mantisbt.c
|
||
|
create mode 100644 src/plugins/mantisbt.conf
|
||
|
create mode 100644 src/plugins/mantisbt.h
|
||
|
create mode 100644 src/plugins/mantisbt_format.conf
|
||
|
create mode 100644 src/plugins/mantisbt_formatdup.conf
|
||
|
create mode 100644 src/plugins/report_CentOSBugTracker.conf
|
||
|
create mode 100644 src/plugins/report_CentOSBugTracker.xml.in
|
||
|
create mode 100644 src/plugins/reporter-mantisbt.c
|
||
|
create mode 100644 src/workflows/report_centos.conf
|
||
|
create mode 100644 src/workflows/workflow_CentOSCCpp.xml.in
|
||
|
create mode 100644 src/workflows/workflow_CentOSJava.xml.in
|
||
|
create mode 100644 src/workflows/workflow_CentOSKerneloops.xml.in
|
||
|
create mode 100644 src/workflows/workflow_CentOSLibreport.xml.in
|
||
|
create mode 100644 src/workflows/workflow_CentOSPython.xml.in
|
||
|
create mode 100644 src/workflows/workflow_CentOSPython3.xml.in
|
||
|
create mode 100644 src/workflows/workflow_CentOSVmcore.xml.in
|
||
|
create mode 100644 src/workflows/workflow_CentOSXorg.xml.in
|
||
|
|
||
|
diff --git a/configure.ac b/configure.ac
|
||
|
index 8aea410..66508c0 100644
|
||
|
--- a/configure.ac
|
||
|
+++ b/configure.ac
|
||
|
@@ -131,6 +131,39 @@ do
|
||
|
done
|
||
|
fi dnl end NO_BUGZILLA
|
||
|
|
||
|
+AC_ARG_WITH(mantisbt,
|
||
|
+AS_HELP_STRING([--with-mantisbt],[use MantisBT plugin (default is YES)]),
|
||
|
+LIBREPORT_PARSE_WITH([mantisbt]))
|
||
|
+
|
||
|
+if test -z "$NO_MANTISBT"; then
|
||
|
+AM_CONDITIONAL(BUILD_MANTISBT, true)
|
||
|
+
|
||
|
+# enable mantisbt & deps translations
|
||
|
+for FILE in `grep -e "#.*antisbt.*" -e "#.*naconda.*" po/POTFILES.in`
|
||
|
+do
|
||
|
+ sed -ie "s,$FILE,${FILE:1}," po/POTFILES.in
|
||
|
+ sed -ie "\,^${FILE:1}$,d" po/POTFILES.skip
|
||
|
+done
|
||
|
+else
|
||
|
+AM_CONDITIONAL(BUILD_MANTISBT, false)
|
||
|
+
|
||
|
+# disablie mantisbt & deps translations
|
||
|
+for FILE in `grep -e "antisbt" -e "naconda" po/POTFILES.in`
|
||
|
+do
|
||
|
+ if test "${FILE:0:1}" = "#"
|
||
|
+ then
|
||
|
+ continue
|
||
|
+ fi
|
||
|
+
|
||
|
+ sed -ie "s,$FILE,#$FILE," po/POTFILES.in
|
||
|
+ grep "$FILE" po/POTFILES.skip > /dev/null 2>&1
|
||
|
+ if test $?
|
||
|
+ then
|
||
|
+ echo "$FILE" >> po/POTFILES.skip
|
||
|
+ fi
|
||
|
+done
|
||
|
+fi dnl end NO_MANTISBT
|
||
|
+
|
||
|
AC_PATH_PROG([PYTHON_CONFIG], [python-config], [no])
|
||
|
[if test "$PYTHON_CONFIG" = "no"]
|
||
|
[then]
|
||
|
diff --git a/po/POTFILES.in b/po/POTFILES.in
|
||
|
index 5588540..3415b03 100644
|
||
|
--- a/po/POTFILES.in
|
||
|
+++ b/po/POTFILES.in
|
||
|
@@ -36,6 +36,8 @@ src/plugins/reporter-print.c
|
||
|
src/plugins/reporter-rhtsupport.c
|
||
|
src/plugins/reporter-rhtsupport-parse.c
|
||
|
src/plugins/reporter-upload.c
|
||
|
+src/plugins/reporter-mantisbt.c
|
||
|
+src/plugins/report_CentOSBugTracker.xml.in
|
||
|
src/plugins/report_Kerneloops.xml.in
|
||
|
src/plugins/report_Logger.xml.in
|
||
|
src/plugins/report_Mailx.xml.in
|
||
|
@@ -44,12 +46,21 @@ src/plugins/report_Uploader.xml.in
|
||
|
src/plugins/report_uReport.xml.in
|
||
|
src/plugins/report_EmergencyAnalysis.xml.in
|
||
|
src/plugins/rhbz.c
|
||
|
+src/plugins/mantisbt.c
|
||
|
src/plugins/reporter-ureport.c
|
||
|
src/report-newt/report-newt.c
|
||
|
src/workflows/workflow_AnacondaFedora.xml.in
|
||
|
src/workflows/workflow_AnacondaRHEL.xml.in
|
||
|
src/workflows/workflow_AnacondaRHELBugzilla.xml.in
|
||
|
src/workflows/workflow_AnacondaUpload.xml.in
|
||
|
+src/workflows/workflow_CentOSCCpp.xml.in
|
||
|
+src/workflows/workflow_CentOSJava.xml.in
|
||
|
+src/workflows/workflow_CentOSKerneloops.xml.in
|
||
|
+src/workflows/workflow_CentOSLibreport.xml.in
|
||
|
+src/workflows/workflow_CentOSPython.xml.in
|
||
|
+src/workflows/workflow_CentOSPython3.xml.in
|
||
|
+src/workflows/workflow_CentOSVmcore.xml.in
|
||
|
+src/workflows/workflow_CentOSXorg.xml.in
|
||
|
src/workflows/workflow_FedoraCCpp.xml.in
|
||
|
src/workflows/workflow_FedoraKerneloops.xml.in
|
||
|
src/workflows/workflow_FedoraPython.xml.in
|
||
|
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
|
||
|
index 7ec08d7..d70b4db 100644
|
||
|
--- a/src/plugins/Makefile.am
|
||
|
+++ b/src/plugins/Makefile.am
|
||
|
@@ -7,6 +7,11 @@ reporters_bin += \
|
||
|
report
|
||
|
endif
|
||
|
|
||
|
+if BUILD_MANTISBT
|
||
|
+reporters_bin += \
|
||
|
+ reporter-mantisbt
|
||
|
+endif
|
||
|
+
|
||
|
if BUILD_UREPORT
|
||
|
reporters_bin += reporter-ureport
|
||
|
endif
|
||
|
@@ -34,6 +39,12 @@ reporters_plugin_format_conf += bugzilla_format.conf \
|
||
|
bugzilla_formatdup_anaconda.conf
|
||
|
endif
|
||
|
|
||
|
+if BUILD_MANTISBT
|
||
|
+reporters_plugin_conf += mantisbt.conf
|
||
|
+reporters_plugin_format_conf += mantisbt_format.conf \
|
||
|
+ mantisbt_formatdup.conf
|
||
|
+endif
|
||
|
+
|
||
|
defaultreportpluginsconfdir = $(DEFAULT_REPORT_PLUGINS_CONF_DIR)
|
||
|
dist_defaultreportpluginsconf_DATA = $(reporters_plugin_conf) \
|
||
|
rhtsupport.conf \
|
||
|
@@ -53,6 +64,12 @@ reporters_events += report_Bugzilla.xml
|
||
|
reporters_events_conf += report_Bugzilla.conf
|
||
|
endif
|
||
|
|
||
|
+if BUILD_MANTISBT
|
||
|
+reporters_events += report_CentOSBugTracker.xml
|
||
|
+
|
||
|
+reporters_events_conf += report_CentOSBugTracker.conf
|
||
|
+endif
|
||
|
+
|
||
|
if BUILD_UREPORT
|
||
|
reporters_events += report_uReport.xml
|
||
|
endif
|
||
|
@@ -77,7 +94,8 @@ dist_eventsdef_DATA = \
|
||
|
print_event.conf \
|
||
|
rhtsupport_event.conf \
|
||
|
uploader_event.conf \
|
||
|
- emergencyanalysis_event.conf
|
||
|
+ emergencyanalysis_event.conf \
|
||
|
+ centos_report_event.conf
|
||
|
|
||
|
reporters_extra_dist =
|
||
|
if BUILD_BUGZILLA
|
||
|
@@ -125,6 +143,29 @@ reporter_bugzilla_LDADD = \
|
||
|
../lib/libreport.la
|
||
|
endif
|
||
|
|
||
|
+if BUILD_MANTISBT
|
||
|
+reporter_mantisbt_SOURCES = \
|
||
|
+ reporter-mantisbt.c mantisbt.c mantisbt.h
|
||
|
+reporter_mantisbt_CPPFLAGS = \
|
||
|
+ -I$(srcdir)/../include \
|
||
|
+ -I$(srcdir)/../lib \
|
||
|
+ -DBIN_DIR=\"$(bindir)\" \
|
||
|
+ -DCONF_DIR=\"$(CONF_DIR)\" \
|
||
|
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
|
||
|
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
|
||
|
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
|
||
|
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
|
||
|
+ -DPLUGINS_CONF_DIR=\"$(REPORT_PLUGINS_CONF_DIR)\" \
|
||
|
+ $(GLIB_CFLAGS) \
|
||
|
+ $(LIBREPORT_CFLAGS) \
|
||
|
+ $(LIBXML_CFLAGS) \
|
||
|
+ -D_GNU_SOURCE
|
||
|
+reporter_mantisbt_LDADD = \
|
||
|
+ $(GLIB_LIBS) \
|
||
|
+ ../lib/libreport-web.la \
|
||
|
+ ../lib/libreport.la
|
||
|
+endif
|
||
|
+
|
||
|
reporter_rhtsupport_SOURCES = \
|
||
|
abrt_rh_support.h abrt_rh_support.c \
|
||
|
reporter-rhtsupport.h \
|
||
|
diff --git a/src/plugins/centos_report_event.conf b/src/plugins/centos_report_event.conf
|
||
|
new file mode 100644
|
||
|
index 0000000..53f12d8
|
||
|
--- /dev/null
|
||
|
+++ b/src/plugins/centos_report_event.conf
|
||
|
@@ -0,0 +1,37 @@
|
||
|
+EVENT=report_CentOSBugTracker analyzer=xorg
|
||
|
+ reporter-mantisbt
|
||
|
+
|
||
|
+EVENT=report_CentOSBugTracker analyzer=Kerneloops
|
||
|
+ reporter-mantisbt
|
||
|
+
|
||
|
+EVENT=report_CentOSBugTracker analyzer=vmcore
|
||
|
+ reporter-mantisbt
|
||
|
+
|
||
|
+EVENT=report_CentOSBugTracker analyzer=Python component!=anaconda
|
||
|
+ test -f component || abrt-action-save-package-data
|
||
|
+ reporter-mantisbt \
|
||
|
+ -c /etc/libreport/plugins/mantisbt.conf \
|
||
|
+ -F /etc/libreport/plugins/mantisbt_format.conf \
|
||
|
+ -A /etc/libreport/plugins/mantisbt_formatdup.conf
|
||
|
+
|
||
|
+EVENT=report_CentOSBugTracker analyzer=Python3 component!=anaconda
|
||
|
+ test -f component || abrt-action-save-package-data
|
||
|
+ reporter-mantisbt \
|
||
|
+ -c /etc/libreport/plugins/mantisbt.conf \
|
||
|
+ -F /etc/libreport/plugins/mantisbt_format.conf \
|
||
|
+ -A /etc/libreport/plugins/mantisbt_formatdup.conf
|
||
|
+
|
||
|
+EVENT=report_CentOSBugTracker analyzer=CCpp duphash!=
|
||
|
+ test -f component || abrt-action-save-package-data
|
||
|
+ component="`cat component`"
|
||
|
+ format="mantisbt_format.conf"
|
||
|
+ test -f "/etc/libreport/plugins/mantisbt_format_$component.conf" \
|
||
|
+ && format="mantisbt_format_$component.conf"
|
||
|
+ formatdup="mantisbt_formatdup.conf"
|
||
|
+ test -f "/etc/libreport/plugins/mantisbt_formatdup_$component.conf" \
|
||
|
+ && formatdup="mantisbt_formatdup_$component.conf"
|
||
|
+ reporter-mantisbt \
|
||
|
+ -c /etc/libreport/plugins/mantisbt.conf \
|
||
|
+ -F "/etc/libreport/plugins/$format" \
|
||
|
+ -A "/etc/libreport/plugins/$formatdup"
|
||
|
+
|
||
|
diff --git a/src/plugins/mantisbt.c b/src/plugins/mantisbt.c
|
||
|
new file mode 100644
|
||
|
index 0000000..1c496b4
|
||
|
--- /dev/null
|
||
|
+++ b/src/plugins/mantisbt.c
|
||
|
@@ -0,0 +1,1111 @@
|
||
|
+/*
|
||
|
+ Copyright (C) 2014 ABRT team
|
||
|
+ Copyright (C) 2014 RedHat Inc
|
||
|
+
|
||
|
+ 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 2 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, write to the Free Software Foundation, Inc.,
|
||
|
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
+*/
|
||
|
+
|
||
|
+#include <curl/curl.h>
|
||
|
+
|
||
|
+#include <libxml/xmlreader.h>
|
||
|
+
|
||
|
+#include "internal_libreport.h"
|
||
|
+#include "libreport_curl.h"
|
||
|
+#include "mantisbt.h"
|
||
|
+#include "client.h"
|
||
|
+
|
||
|
+/*
|
||
|
+ * SOAP
|
||
|
+*/
|
||
|
+
|
||
|
+#define XML_VERSION "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||
|
+
|
||
|
+/* fprint string */
|
||
|
+#define SOAP_TEMPLATE \
|
||
|
+ "<SOAP-ENV:Envelope xmlns:ns3=\"http://schemas.xmlsoap.org/soap/encoding/\" " \
|
||
|
+ "xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" " \
|
||
|
+ "xmlns:ns0=\"http://schemas.xmlsoap.org/soap/encoding/\" " \
|
||
|
+ "xmlns:ns1=\"http://schemas.xmlsoap.org/soap/envelope/\" " \
|
||
|
+ "xmlns:ns2=\"http://www.w3.org/2001/XMLSchema\" " \
|
||
|
+ "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
|
||
|
+ "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" " \
|
||
|
+ "SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" \
|
||
|
+ "<SOAP-ENV:Header/>" \
|
||
|
+ "<ns1:Body>" \
|
||
|
+ "<ns3:%s>" \
|
||
|
+ "</ns3:%s>" \
|
||
|
+ "</ns1:Body>" \
|
||
|
+ "</SOAP-ENV:Envelope>"
|
||
|
+
|
||
|
+#define MAX_SUMMARY_LENGTH 128
|
||
|
+#define CUSTOMFIELD_DUPHASH "abrt_hash"
|
||
|
+#define CUSTOMFIELD_URL "URL"
|
||
|
+#define MAX_HOPS 5
|
||
|
+
|
||
|
+/* MantisBT limit is 2MB by default
|
||
|
+ */
|
||
|
+#define MANTISBT_MAX_FILE_UPLOAD_SIZE (2 * 1024 * 1024)
|
||
|
+
|
||
|
+typedef struct mantisbt_custom_fields
|
||
|
+{
|
||
|
+ char *cf_abrt_hash_id;
|
||
|
+ char *cf_url_id;
|
||
|
+} mantisbt_custom_fields_t;
|
||
|
+
|
||
|
+/*
|
||
|
+ * MantisBT settings issue info
|
||
|
+ */
|
||
|
+void
|
||
|
+mantisbt_settings_free(mantisbt_settings_t *s)
|
||
|
+{
|
||
|
+ if (s == NULL)
|
||
|
+ return;
|
||
|
+
|
||
|
+ free(s->m_login);
|
||
|
+ free(s->m_password);
|
||
|
+ free(s->m_project);
|
||
|
+ free(s->m_project_id);
|
||
|
+ free(s->m_project_version);
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * MantisBT issue info
|
||
|
+ */
|
||
|
+mantisbt_issue_info_t *
|
||
|
+mantisbt_issue_info_new()
|
||
|
+{
|
||
|
+ mantisbt_issue_info_t *info = xzalloc(sizeof(mantisbt_issue_info_t));
|
||
|
+ info->mii_id = -1;
|
||
|
+ info->mii_dup_id = -1;
|
||
|
+
|
||
|
+ return info;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+mantisbt_issue_info_free(mantisbt_issue_info_t *info)
|
||
|
+{
|
||
|
+ if (info == NULL)
|
||
|
+ return;
|
||
|
+
|
||
|
+ free(info->mii_status);
|
||
|
+ free(info->mii_resolution);
|
||
|
+ free(info->mii_reporter);
|
||
|
+ free(info->mii_project);
|
||
|
+
|
||
|
+ list_free_with_free(info->mii_notes);
|
||
|
+ list_free_with_free(info->mii_attachments);
|
||
|
+
|
||
|
+ free(info);
|
||
|
+}
|
||
|
+
|
||
|
+mantisbt_issue_info_t *
|
||
|
+mantisbt_find_origin_bug_closed_duplicate(mantisbt_settings_t *settings, mantisbt_issue_info_t *info)
|
||
|
+{
|
||
|
+ mantisbt_issue_info_t *info_tmp = mantisbt_issue_info_new();
|
||
|
+ info_tmp->mii_id = info->mii_id;
|
||
|
+ info_tmp->mii_dup_id = info->mii_dup_id;
|
||
|
+
|
||
|
+ for (int ii = 0; ii <= MAX_HOPS; ii++)
|
||
|
+ {
|
||
|
+ if (ii == MAX_HOPS)
|
||
|
+ error_msg_and_die(_("MantisBT couldn't find parent of issue %d"), info->mii_id);
|
||
|
+
|
||
|
+ log("Issue %d is a duplicate, using parent issue %d", info_tmp->mii_id, info_tmp->mii_dup_id);
|
||
|
+ int issue_id = info_tmp->mii_dup_id;
|
||
|
+
|
||
|
+ mantisbt_issue_info_free(info_tmp);
|
||
|
+ info_tmp = mantisbt_get_issue_info(settings, issue_id);
|
||
|
+
|
||
|
+ // found a issue which is not CLOSED as DUPLICATE
|
||
|
+ if (info_tmp->mii_dup_id == -1)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ return info_tmp;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * SOAP request
|
||
|
+ */
|
||
|
+static soap_request_t *
|
||
|
+soap_request_new()
|
||
|
+{
|
||
|
+ soap_request_t *req = xzalloc(sizeof(*req));
|
||
|
+
|
||
|
+ return req;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+soap_request_free(soap_request_t *req)
|
||
|
+{
|
||
|
+ if (req == NULL)
|
||
|
+ return;
|
||
|
+
|
||
|
+ if (req->sr_root != NULL)
|
||
|
+ xmlFreeDoc(req->sr_root->doc);
|
||
|
+
|
||
|
+ free(req);
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+static xmlNodePtr
|
||
|
+soap_node_get_next_element_node(xmlNodePtr node)
|
||
|
+{
|
||
|
+ for (; node != NULL; node = node->next)
|
||
|
+ if (node->type == XML_ELEMENT_NODE)
|
||
|
+ break;
|
||
|
+
|
||
|
+ return node;
|
||
|
+}
|
||
|
+
|
||
|
+static xmlNodePtr
|
||
|
+soap_node_get_child_element(xmlNodePtr node)
|
||
|
+{
|
||
|
+ if (node == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to get child element because of no parent."));
|
||
|
+
|
||
|
+ return soap_node_get_next_element_node(node->xmlChildrenNode);
|
||
|
+}
|
||
|
+
|
||
|
+static xmlNodePtr
|
||
|
+soap_node_get_next_sibling(xmlNodePtr node)
|
||
|
+{
|
||
|
+ if (node == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to get next element because of no node."));
|
||
|
+
|
||
|
+ return soap_node_get_next_element_node(node->next);
|
||
|
+}
|
||
|
+
|
||
|
+static xmlNodePtr
|
||
|
+soap_node_get_child_node(xmlNodePtr parent, const char *name)
|
||
|
+{
|
||
|
+ if (parent == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to get child node because of no parent."));
|
||
|
+
|
||
|
+ xmlNodePtr node;
|
||
|
+ for (node = soap_node_get_child_element(parent); node != NULL; node = soap_node_get_next_sibling(node))
|
||
|
+ {
|
||
|
+ if (xmlStrcmp(node->name, BAD_CAST name) == 0)
|
||
|
+ return node;
|
||
|
+ }
|
||
|
+
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+soap_request_t *
|
||
|
+soap_request_new_for_method(const char *method)
|
||
|
+{
|
||
|
+ char *xml_str = xasprintf(SOAP_TEMPLATE, method, method);
|
||
|
+
|
||
|
+ xmlDocPtr doc = xmlParseDoc(BAD_CAST xml_str);
|
||
|
+ free(xml_str);
|
||
|
+
|
||
|
+ if (doc == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to parse xml during creating request."));
|
||
|
+
|
||
|
+ soap_request_t *req = soap_request_new();
|
||
|
+
|
||
|
+ req->sr_root = xmlDocGetRootElement(doc);
|
||
|
+ if (req->sr_root == NULL)
|
||
|
+ {
|
||
|
+ soap_request_free(req);
|
||
|
+ error_msg_and_die(_("SOAP: Failed to get xml root element."));
|
||
|
+ }
|
||
|
+
|
||
|
+ req->sr_body = soap_node_get_child_node(req->sr_root, "Body");
|
||
|
+ req->sr_method = soap_node_get_child_node(req->sr_body, method);
|
||
|
+
|
||
|
+ return req;
|
||
|
+}
|
||
|
+
|
||
|
+static xmlNodePtr
|
||
|
+soap_node_add_child_node(xmlNodePtr node, const char *name, const char *type, const char *value)
|
||
|
+{
|
||
|
+ if (node == NULL || name == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to add a new child node because of no node or no child name."));
|
||
|
+
|
||
|
+ xmlNodePtr new_node = xmlNewTextChild(node, /* namespace */ NULL, BAD_CAST name, BAD_CAST value);
|
||
|
+
|
||
|
+ if (new_node == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to create a new xml child item."));
|
||
|
+
|
||
|
+ if (type != NULL)
|
||
|
+ {
|
||
|
+ if (xmlNewProp(new_node, BAD_CAST "xsi:type", BAD_CAST type) == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to create a new property."));
|
||
|
+ }
|
||
|
+
|
||
|
+ return new_node;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+soap_request_add_method_parameter(soap_request_t *req, const char *name, const char *type, const char *value)
|
||
|
+{
|
||
|
+ if (req == NULL || req->sr_method == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to add method parametr."));
|
||
|
+
|
||
|
+ soap_node_add_child_node(req->sr_method, name, type, value);
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+soap_request_add_credentials_parameter(soap_request_t *req, const mantisbt_settings_t *settings)
|
||
|
+{
|
||
|
+ soap_request_add_method_parameter(req, "username", SOAP_STRING, settings->m_login);
|
||
|
+ soap_request_add_method_parameter(req, "password", SOAP_STRING, settings->m_password);
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+soap_add_new_issue_parameters(soap_request_t *req,
|
||
|
+ const char *project,
|
||
|
+ const char *version,
|
||
|
+ const char *category,
|
||
|
+ const char *summary,
|
||
|
+ const char *description,
|
||
|
+ const char *additional_information,
|
||
|
+ bool private,
|
||
|
+ mantisbt_custom_fields_t *fields,
|
||
|
+ const char *duphash,
|
||
|
+ const char *tracker_url)
|
||
|
+{
|
||
|
+ if (req == NULL || req->sr_method == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to add new issue parametrs."));
|
||
|
+
|
||
|
+ if (project == NULL || category == NULL || summary == NULL || description == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to add new issue parameters because the required items are missing."));
|
||
|
+
|
||
|
+ xmlNodePtr issue_node = soap_node_add_child_node(req->sr_method, "issue", SOAP_ISSUEDATA, /* content */ NULL);
|
||
|
+
|
||
|
+ // project
|
||
|
+ xmlNodePtr project_node = soap_node_add_child_node(issue_node, "project", SOAP_OBJECTREF, /* content */ NULL);
|
||
|
+ soap_node_add_child_node(project_node, "name", SOAP_STRING, project);
|
||
|
+
|
||
|
+ // view status
|
||
|
+ xmlNodePtr view_node = soap_node_add_child_node(issue_node, "view_state", SOAP_OBJECTREF, /* content */ NULL);
|
||
|
+ soap_node_add_child_node(view_node, "name", SOAP_STRING, (private) ? "private" : "public");
|
||
|
+
|
||
|
+ /* if any custom field exists */
|
||
|
+ int custom_fields_count = 0;
|
||
|
+ xmlNodePtr duphash_node;
|
||
|
+ if (fields->cf_abrt_hash_id != NULL || fields->cf_url_id != NULL)
|
||
|
+ duphash_node = soap_node_add_child_node(issue_node, "custom_fields", SOAP_CUSTOMFIELD_ARRAY, /* content */ NULL);
|
||
|
+
|
||
|
+ // custom fields (duphash and URL to tracker)
|
||
|
+ xmlNodePtr item_node, field_node;
|
||
|
+ if (fields->cf_abrt_hash_id != NULL)
|
||
|
+ {
|
||
|
+ item_node = soap_node_add_child_node(duphash_node, "item", SOAP_CUSTOMFIELD, /* content */ NULL);
|
||
|
+ field_node = soap_node_add_child_node(item_node, "field", SOAP_OBJECTREF, /* content */ NULL);
|
||
|
+ soap_node_add_child_node(field_node, "id", SOAP_INTEGER, /* custom_field id */ fields->cf_abrt_hash_id);
|
||
|
+ soap_node_add_child_node(item_node, "value", SOAP_STRING, duphash);
|
||
|
+ ++custom_fields_count;
|
||
|
+ }
|
||
|
+
|
||
|
+ // if tracker url exists, attach it to the issue
|
||
|
+ if (tracker_url != NULL && fields->cf_url_id != NULL)
|
||
|
+ {
|
||
|
+ item_node = soap_node_add_child_node(duphash_node, "item", SOAP_CUSTOMFIELD, /* content */ NULL);
|
||
|
+ field_node = soap_node_add_child_node(item_node, "field", SOAP_OBJECTREF, /* content */ NULL);
|
||
|
+ soap_node_add_child_node(field_node, "id", SOAP_INTEGER, /* custom_field */ fields->cf_url_id);
|
||
|
+ soap_node_add_child_node(item_node, "value", SOAP_STRING, tracker_url);
|
||
|
+ ++custom_fields_count;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (custom_fields_count > 0)
|
||
|
+ {
|
||
|
+ char *type = xasprintf("%s[%i]", SOAP_CUSTOMFIELD, custom_fields_count);
|
||
|
+
|
||
|
+ if (xmlNewProp(duphash_node, BAD_CAST "ns3:arrayType", BAD_CAST type) == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to create a new property in custom fields."));
|
||
|
+
|
||
|
+ free(type);
|
||
|
+ }
|
||
|
+
|
||
|
+ soap_node_add_child_node(issue_node, "os_build", SOAP_STRING, version);
|
||
|
+ soap_node_add_child_node(issue_node, "category", SOAP_STRING, category);
|
||
|
+ soap_node_add_child_node(issue_node, "summary", SOAP_STRING, summary);
|
||
|
+ soap_node_add_child_node(issue_node, "description", SOAP_STRING, description);
|
||
|
+ soap_node_add_child_node(issue_node, "additional_information", SOAP_STRING, additional_information);
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+char *
|
||
|
+soap_request_to_str(const soap_request_t *req)
|
||
|
+{
|
||
|
+ if (req == NULL || req->sr_root == NULL || req->sr_root->doc == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to create SOAP string because of invalid function arguments."));
|
||
|
+
|
||
|
+ xmlBufferPtr buffer = xmlBufferCreate();
|
||
|
+ int err = xmlNodeDump(buffer, req->sr_root->doc, req->sr_root, 1, /* formatting */ 0);
|
||
|
+ if (err == -1)
|
||
|
+ {
|
||
|
+ xmlBufferFree(buffer);
|
||
|
+ error_msg_and_die(_("SOAP: Failed to dump xml node."));
|
||
|
+ }
|
||
|
+
|
||
|
+ char *ret = xasprintf("%s%s", XML_VERSION, (const char *) xmlBufferContent(buffer));
|
||
|
+ xmlBufferFree(buffer);
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+#if 0
|
||
|
+void
|
||
|
+soap_request_print(soap_request_t *req)
|
||
|
+{
|
||
|
+ if (req == NULL || req->sr_root == NULL || req->sr_root->doc == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to print SOAP string."));
|
||
|
+
|
||
|
+ xmlBufferPtr buffer = xmlBufferCreate();
|
||
|
+ int err = xmlNodeDump(buffer, req->sr_root->doc, req->sr_root, 1, /* formatting */ 0);
|
||
|
+ if (err == -1)
|
||
|
+ {
|
||
|
+ xmlBufferFree(buffer);
|
||
|
+ error_msg_and_die(_("Failed to dump xml node."));
|
||
|
+ }
|
||
|
+
|
||
|
+ puts((const char *) xmlBufferContent(buffer));
|
||
|
+
|
||
|
+ xmlBufferFree(buffer);
|
||
|
+ return;
|
||
|
+}
|
||
|
+#endif
|
||
|
+
|
||
|
+static bool
|
||
|
+reader_move_reader_if_node_type_is_element_with_name_and_verify_its_value(xmlTextReaderPtr reader, const char *name)
|
||
|
+{
|
||
|
+ /* is not element node */
|
||
|
+ if (xmlTextReaderNodeType(reader) != XML_ELEMENT_NODE)
|
||
|
+ return false;
|
||
|
+
|
||
|
+ /* is not required name */
|
||
|
+ if (xmlStrcmp(xmlTextReaderConstName(reader), BAD_CAST name) != 0)
|
||
|
+ return false;
|
||
|
+
|
||
|
+ /* read next node */
|
||
|
+ if (xmlTextReaderRead(reader) != 1)
|
||
|
+ return false;
|
||
|
+
|
||
|
+ /* no value node */
|
||
|
+ if (xmlTextReaderHasValue(reader) == 0)
|
||
|
+ return false;
|
||
|
+
|
||
|
+ /* no text node */
|
||
|
+ if (xmlTextReaderNodeType(reader) != XML_TEXT_NODE)
|
||
|
+ return false;
|
||
|
+
|
||
|
+ return true;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+reader_find_element_by_name(xmlTextReaderPtr reader, const char *name)
|
||
|
+{
|
||
|
+ while (xmlTextReaderRead(reader) == 1)
|
||
|
+ {
|
||
|
+ /* is not element node */
|
||
|
+ if (xmlTextReaderNodeType(reader) != XML_ELEMENT_NODE)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ /* is not required name */
|
||
|
+ if (xmlStrcmp(xmlTextReaderConstName(reader), BAD_CAST name) != 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+/* It is not possible to search only by name because the response contains
|
||
|
+ * different node with the same name. (e.g. id - user id, project id, issue id etc.)
|
||
|
+ * We are interested in only about issues id which is located at a different depth than others.
|
||
|
+ * ...
|
||
|
+ * <item xsi:type="ns1:IssueData">
|
||
|
+ * <id xsi:type="xsd:integer">10</id> <-- This is issue ID (required)
|
||
|
+ * <view_state xsi:type="ns1:ObjectRef">
|
||
|
+ * <id xsi:type="xsd:integer">10</id> <-- This is view_state ID (not required)
|
||
|
+ * <name xsi:type="xsd:string">public</name>
|
||
|
+ * </view_state>
|
||
|
+ * <project xsi:type="ns1:ObjectRef">
|
||
|
+ * <id xsi:type="xsd:integer">1</id> <-- This is project ID (not required)
|
||
|
+ * <name xsi:type="xsd:string">test</name>
|
||
|
+ * </project>
|
||
|
+ * ...
|
||
|
+ */
|
||
|
+static GList *
|
||
|
+response_values_at_depth_by_name(const char *xml, const char *name, int depth)
|
||
|
+{
|
||
|
+ xmlDocPtr doc = xmlParseDoc(BAD_CAST xml);
|
||
|
+ if (doc == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to parse xml (searching value at depth by name)."));
|
||
|
+
|
||
|
+ xmlTextReaderPtr reader = xmlReaderWalker(doc);
|
||
|
+ if (reader == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to create xml text reader."));
|
||
|
+
|
||
|
+ GList *result = NULL;
|
||
|
+
|
||
|
+ const xmlChar *value;
|
||
|
+ while (xmlTextReaderRead(reader) == 1)
|
||
|
+ {
|
||
|
+ /* is not right depth */
|
||
|
+ if (depth != -1 && xmlTextReaderDepth(reader) != depth)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (reader_move_reader_if_node_type_is_element_with_name_and_verify_its_value(reader, name) == false)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if ((value = xmlTextReaderConstValue(reader)) != NULL)
|
||
|
+ result = g_list_append(result, xstrdup((const char *) value));
|
||
|
+ }
|
||
|
+ xmlFreeTextReader(reader);
|
||
|
+
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Finds an element named 'elem' and returns a text of a child named 'name'
|
||
|
+ *
|
||
|
+ * Example:
|
||
|
+ * For
|
||
|
+ * <elem>
|
||
|
+ * <id>1</id>
|
||
|
+ * <name>foo</name>
|
||
|
+ * </elem>
|
||
|
+ *
|
||
|
+ * returns "foo"
|
||
|
+ */
|
||
|
+static char *
|
||
|
+response_get_name_value_of_element(const char *xml, const char *element)
|
||
|
+{
|
||
|
+ xmlDocPtr doc = xmlParseDoc(BAD_CAST xml);
|
||
|
+ if (doc == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to parse xml."));
|
||
|
+
|
||
|
+ xmlTextReaderPtr reader = xmlReaderWalker(doc);
|
||
|
+ if (reader == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to create xml text reader."));
|
||
|
+
|
||
|
+ const xmlChar *value = NULL;
|
||
|
+
|
||
|
+ reader_find_element_by_name(reader, element);
|
||
|
+
|
||
|
+ /* find 'name' element and return its text */
|
||
|
+ while (xmlTextReaderRead(reader) == 1)
|
||
|
+ {
|
||
|
+ if (reader_move_reader_if_node_type_is_element_with_name_and_verify_its_value(reader, "name") == false)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if ((value = xmlTextReaderConstValue(reader)) != NULL)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ xmlFreeTextReader(reader);
|
||
|
+
|
||
|
+ return (char *) value;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+response_get_id_of_relatedto_issue(const char *xml)
|
||
|
+{
|
||
|
+ xmlDocPtr doc = xmlParseDoc(BAD_CAST xml);
|
||
|
+ if (doc == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to parse xml (get related to issue)."));
|
||
|
+
|
||
|
+ xmlTextReaderPtr reader = xmlReaderWalker(doc);
|
||
|
+ if (reader == NULL)
|
||
|
+ error_msg_and_die(_("SOAP: Failed to create xml text reader."));
|
||
|
+
|
||
|
+ const xmlChar *value = NULL;
|
||
|
+ const xmlChar *id = NULL;
|
||
|
+
|
||
|
+ /* find relationships section */
|
||
|
+ reader_find_element_by_name(reader, "relationships");
|
||
|
+
|
||
|
+ /* find "name" value of 'name' element */
|
||
|
+ while (xmlTextReaderRead(reader) == 1)
|
||
|
+ {
|
||
|
+ /* find type of relattionship */
|
||
|
+ if (reader_move_reader_if_node_type_is_element_with_name_and_verify_its_value(reader, "name") == false)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if ((value = xmlTextReaderConstValue(reader)) == NULL)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ /* we need 'duplicate of' realtionship type */
|
||
|
+ if (xmlStrcmp(value, BAD_CAST "duplicate of") != 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ /* find id of duplicate issues */
|
||
|
+ reader_find_element_by_name(reader, "target_id");
|
||
|
+
|
||
|
+ /* verify target_id node */
|
||
|
+ if (reader_move_reader_if_node_type_is_element_with_name_and_verify_its_value(reader, "target_id") == false)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ /* get its value */
|
||
|
+ if ((id = xmlTextReaderConstValue(reader)) != NULL)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ xmlFreeTextReader(reader);
|
||
|
+
|
||
|
+ return (id == NULL) ? -1 : atoi((const char *) id);
|
||
|
+}
|
||
|
+
|
||
|
+GList *
|
||
|
+response_get_main_ids_list(const char *xml)
|
||
|
+{
|
||
|
+ return response_values_at_depth_by_name(xml, "id", 5);
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+response_get_main_id(const char *xml)
|
||
|
+{
|
||
|
+ GList *l = response_values_at_depth_by_name(xml, "id", 5);
|
||
|
+ return (l != NULL) ? atoi(l->data) : -1;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+response_get_return_value(const char *xml)
|
||
|
+{
|
||
|
+ GList *l = response_values_at_depth_by_name(xml, "return", 3);
|
||
|
+ return (l != NULL) ? atoi(l->data) : -1;
|
||
|
+}
|
||
|
+
|
||
|
+static char*
|
||
|
+response_get_return_value_as_string(const char *xml)
|
||
|
+{
|
||
|
+ GList *l = response_values_at_depth_by_name(xml, "return", 3);
|
||
|
+ return (l != NULL) ? l->data : NULL;
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+response_get_error_msg(const char *xml)
|
||
|
+{
|
||
|
+ GList *l = response_values_at_depth_by_name(xml, "faultstring", 3);
|
||
|
+ return (l != NULL) ? xstrdup(l->data) : NULL;
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+response_get_additioanl_information(const char *xml)
|
||
|
+{
|
||
|
+ GList *l = response_values_at_depth_by_name(xml, "additional_information", -1);
|
||
|
+ return (l != NULL) ? xstrdup(l->data) : NULL;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+response_values_free(GList *values)
|
||
|
+{
|
||
|
+ g_list_free_full(values, free);
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * POST
|
||
|
+ */
|
||
|
+
|
||
|
+void
|
||
|
+mantisbt_result_free(mantisbt_result_t *result)
|
||
|
+{
|
||
|
+ if (result == NULL)
|
||
|
+ return;
|
||
|
+
|
||
|
+ free(result->mr_url);
|
||
|
+ free(result->mr_msg);
|
||
|
+ free(result->mr_body);
|
||
|
+ free(result);
|
||
|
+}
|
||
|
+
|
||
|
+mantisbt_result_t *
|
||
|
+mantisbt_soap_call(const mantisbt_settings_t *settings, const soap_request_t *req)
|
||
|
+{
|
||
|
+ char *request = soap_request_to_str(req);
|
||
|
+
|
||
|
+ const char *url = settings->m_mantisbt_soap_url;
|
||
|
+
|
||
|
+ mantisbt_result_t *result = xzalloc(sizeof(*result));
|
||
|
+
|
||
|
+ if (url == NULL || request == NULL)
|
||
|
+ {
|
||
|
+ result->mr_error = -2;
|
||
|
+ result->mr_msg = xasprintf(_("Url or request isn't specified."));
|
||
|
+ free(request);
|
||
|
+
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
+ char *url_copy = NULL;
|
||
|
+
|
||
|
+ int redirect_count = 0;
|
||
|
+ char *errmsg;
|
||
|
+ post_state_t *post_state;
|
||
|
+
|
||
|
+redirect:
|
||
|
+ post_state = new_post_state(0
|
||
|
+ + POST_WANT_HEADERS
|
||
|
+ + POST_WANT_BODY
|
||
|
+ + POST_WANT_ERROR_MSG
|
||
|
+ + (settings->m_ssl_verify ? POST_WANT_SSL_VERIFY : 0)
|
||
|
+ );
|
||
|
+
|
||
|
+ post_string(post_state, settings->m_mantisbt_soap_url, "text/xml", NULL, request);
|
||
|
+
|
||
|
+ char *location = find_header_in_post_state(post_state, "Location:");
|
||
|
+
|
||
|
+ switch (post_state->http_resp_code)
|
||
|
+ {
|
||
|
+ case 404:
|
||
|
+ result->mr_error = -1;
|
||
|
+ result->mr_msg = xasprintf(_("Error in HTTP POST, "
|
||
|
+ "HTTP code: 404 (Not found), URL:'%s'"), url);
|
||
|
+ break;
|
||
|
+ case 500:
|
||
|
+ result->mr_error = -1;
|
||
|
+ result->mr_msg = response_get_error_msg(post_state->body);
|
||
|
+
|
||
|
+ break;
|
||
|
+ case 301: /* "301 Moved Permanently" (for example, used to move http:// to https://) */
|
||
|
+ case 302: /* "302 Found" (just in case) */
|
||
|
+ case 305: /* "305 Use Proxy" */
|
||
|
+ if (++redirect_count < 10 && location)
|
||
|
+ {
|
||
|
+ free(url_copy);
|
||
|
+ url = url_copy = xstrdup(location);
|
||
|
+ free_post_state(post_state);
|
||
|
+ goto redirect;
|
||
|
+ }
|
||
|
+ /* fall through */
|
||
|
+
|
||
|
+ default:
|
||
|
+ result->mr_error = -1;
|
||
|
+ errmsg = post_state->curl_error_msg;
|
||
|
+ if (errmsg && errmsg[0])
|
||
|
+ result->mr_msg = xasprintf(_("Error in MantisBT request at '%s': %s"), url, errmsg);
|
||
|
+ else
|
||
|
+ result->mr_msg = xasprintf(_("Error in MantisBT request at '%s'"), url);
|
||
|
+ break;
|
||
|
+
|
||
|
+ case 200:
|
||
|
+ case 201:
|
||
|
+ /* sent successfully */
|
||
|
+ result->mr_url = xstrdup(location); /* note: xstrdup(NULL) returns NULL */
|
||
|
+ } /* switch (HTTP code) */
|
||
|
+
|
||
|
+ result->mr_http_resp_code = post_state->http_resp_code;
|
||
|
+ result->mr_body = post_state->body;
|
||
|
+ post_state->body = NULL;
|
||
|
+
|
||
|
+ free_post_state(post_state);
|
||
|
+ free(url_copy);
|
||
|
+ free(request);
|
||
|
+
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+mantisbt_attach_data(const mantisbt_settings_t *settings, const char *bug_id,
|
||
|
+ const char *att_name, const char *data, int size)
|
||
|
+{
|
||
|
+ soap_request_t *req = soap_request_new_for_method("mc_issue_attachment_add");
|
||
|
+ soap_request_add_credentials_parameter(req, settings);
|
||
|
+
|
||
|
+ soap_request_add_method_parameter(req, "issue_id", SOAP_INTEGER, bug_id);
|
||
|
+ soap_request_add_method_parameter(req, "name", SOAP_STRING, att_name);
|
||
|
+
|
||
|
+ soap_request_add_method_parameter(req, "file_type", SOAP_STRING, "text");
|
||
|
+ soap_request_add_method_parameter(req, "content", SOAP_BASE64, encode_base64(data, size));
|
||
|
+
|
||
|
+ mantisbt_result_t *result = mantisbt_soap_call(settings, req);
|
||
|
+ soap_request_free(req);
|
||
|
+
|
||
|
+ if (result->mr_http_resp_code != 200)
|
||
|
+ {
|
||
|
+ int ret = -1;
|
||
|
+ if (strcmp(result->mr_msg, "Duplicate filename.") == 0)
|
||
|
+ ret = -2;
|
||
|
+
|
||
|
+ error_msg(_("Failed to attach file: '%s'"), result->mr_msg);
|
||
|
+ mantisbt_result_free(result);
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ int id = response_get_return_value(result->mr_body);
|
||
|
+
|
||
|
+ mantisbt_result_free(result);
|
||
|
+
|
||
|
+ return id;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+mantisbt_attach_fd(const mantisbt_settings_t *settings, const char *bug_id,
|
||
|
+ const char *att_name, int fd)
|
||
|
+{
|
||
|
+ off_t size = lseek(fd, 0, SEEK_END);
|
||
|
+ if (size < 0)
|
||
|
+ {
|
||
|
+ perror_msg(_("Can't lseek '%s'"), att_name);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (size >= MANTISBT_MAX_FILE_UPLOAD_SIZE)
|
||
|
+ {
|
||
|
+ error_msg(_("Can't upload '%s', it's too large (%llu bytes)"), att_name, (long long)size);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ lseek(fd, 0, SEEK_SET);
|
||
|
+
|
||
|
+ char *data = xmalloc(size + 1);
|
||
|
+ ssize_t r = full_read(fd, data, size);
|
||
|
+ if (r < 0)
|
||
|
+ {
|
||
|
+ free(data);
|
||
|
+ perror_msg(_("Can't read '%s'"), att_name);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ int res = mantisbt_attach_data(settings, bug_id, att_name, data, size);
|
||
|
+ free(data);
|
||
|
+ return res;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+mantisbt_attach_file(const mantisbt_settings_t *settings, const char *bug_id,
|
||
|
+ const char *att_name, const char *path)
|
||
|
+{
|
||
|
+ int fd = open(path, O_RDONLY);
|
||
|
+ if (fd < 0)
|
||
|
+ {
|
||
|
+ perror_msg(_("Can't open '%s'"), path);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ errno = 0;
|
||
|
+ struct stat st;
|
||
|
+ if (fstat(fd, &st) != 0 || !S_ISREG(st.st_mode))
|
||
|
+ {
|
||
|
+ perror_msg("'%s': not a regular file", path);
|
||
|
+ close(fd);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ log_debug("attaching '%s' as file", att_name);
|
||
|
+ int ret = mantisbt_attach_fd(settings, bug_id, att_name, fd);
|
||
|
+ close(fd);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+soap_filter_add_new_array_parameter(xmlNodePtr filter_node, const char *name, const char *type, const char *value)
|
||
|
+{
|
||
|
+ const char *array_type = NULL;
|
||
|
+ if( strcmp(type, SOAP_INTEGER) == 0 )
|
||
|
+ array_type = SOAP_INTEGERARRAY;
|
||
|
+ else
|
||
|
+ array_type = SOAP_STRINGARRAY;
|
||
|
+
|
||
|
+ xmlNodePtr filter_item = soap_node_add_child_node(filter_node, name, array_type, /* content */ NULL);
|
||
|
+ soap_node_add_child_node(filter_item, "item", type, value);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+soap_filter_custom_fields_add_new_item(xmlNodePtr filter_node, const char *custom_field_name, const char *value)
|
||
|
+{
|
||
|
+ xmlNodePtr item_node = soap_node_add_child_node(filter_node, "item", SOAP_FILTER_CUSTOMFIELD, /* content */ NULL);
|
||
|
+
|
||
|
+ xmlNodePtr field_node = soap_node_add_child_node(item_node, "field", SOAP_OBJECTREF, /* content */ NULL);
|
||
|
+ soap_node_add_child_node(field_node, "name", SOAP_STRING, custom_field_name);
|
||
|
+
|
||
|
+ xmlNodePtr value_node = soap_node_add_child_node(item_node, "value", SOAP_STRINGARRAY, /* content */ NULL);
|
||
|
+ soap_node_add_child_node(value_node, "item", SOAP_STRING, value);
|
||
|
+}
|
||
|
+
|
||
|
+GList *
|
||
|
+mantisbt_search_by_abrt_hash(mantisbt_settings_t *settings, const char *abrt_hash)
|
||
|
+{
|
||
|
+ soap_request_t *req = soap_request_new_for_method("mc_filter_search_issues");
|
||
|
+ soap_request_add_credentials_parameter(req, settings);
|
||
|
+
|
||
|
+ xmlNodePtr filter_node = soap_node_add_child_node(req->sr_method, "filter", SOAP_FILTER_SEARCH_DATA, /* content */ NULL);
|
||
|
+
|
||
|
+ /* 'hide_status_is : -2' means, searching within all status */
|
||
|
+ soap_filter_add_new_array_parameter(filter_node, "hide_status_id", SOAP_INTEGERARRAY, "-2");
|
||
|
+
|
||
|
+ // custom fields
|
||
|
+ xmlNodePtr custom_fields_node = soap_node_add_child_node(filter_node, "custom_fields", SOAP_FILTER_CUSTOMFIELD_ARRAY, /* content */ NULL);
|
||
|
+
|
||
|
+ // custom field 'abrt_hash'
|
||
|
+ soap_filter_custom_fields_add_new_item(custom_fields_node, "abrt_hash", abrt_hash);
|
||
|
+
|
||
|
+ soap_request_add_method_parameter(req, "page_number", SOAP_INTEGER, "1");
|
||
|
+ soap_request_add_method_parameter(req, "per_page", SOAP_INTEGER, /* -1 means get all issues */ "-1");
|
||
|
+
|
||
|
+ mantisbt_result_t *result = mantisbt_soap_call(settings, req);
|
||
|
+ soap_request_free(req);
|
||
|
+
|
||
|
+ if (result->mr_error == -1)
|
||
|
+ {
|
||
|
+ error_msg(_("Failed to search MantisBT issue by duphash: '%s'"), result->mr_msg);
|
||
|
+ mantisbt_result_free(result);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ GList *ids = response_get_main_ids_list(result->mr_body);
|
||
|
+
|
||
|
+ return ids;
|
||
|
+}
|
||
|
+
|
||
|
+GList *
|
||
|
+mantisbt_search_duplicate_issues(mantisbt_settings_t *settings, const char *category,
|
||
|
+ const char *version, const char *abrt_hash)
|
||
|
+{
|
||
|
+ soap_request_t *req = soap_request_new_for_method("mc_filter_search_issues");
|
||
|
+ soap_request_add_credentials_parameter(req, settings);
|
||
|
+
|
||
|
+ xmlNodePtr filter_node = soap_node_add_child_node(req->sr_method, "filter", SOAP_FILTER_SEARCH_DATA, /* content */ NULL);
|
||
|
+
|
||
|
+ soap_filter_add_new_array_parameter(filter_node, "project_id", SOAP_INTEGERARRAY, settings->m_project_id);
|
||
|
+
|
||
|
+ /* 'hide_status_is : -2' means, searching within all status */
|
||
|
+ soap_filter_add_new_array_parameter(filter_node, "hide_status_id", SOAP_INTEGERARRAY, "-2");
|
||
|
+
|
||
|
+ soap_filter_add_new_array_parameter(filter_node, "category", SOAP_STRINGARRAY, category);
|
||
|
+
|
||
|
+ // custom fields
|
||
|
+ xmlNodePtr custom_fields_node = soap_node_add_child_node(filter_node, "custom_fields", SOAP_FILTER_CUSTOMFIELD_ARRAY, /* content */ NULL);
|
||
|
+
|
||
|
+ // custom field 'abrt_hash'
|
||
|
+ soap_filter_custom_fields_add_new_item(custom_fields_node, "abrt_hash", abrt_hash);
|
||
|
+
|
||
|
+ // version
|
||
|
+ if (version != NULL)
|
||
|
+ soap_filter_add_new_array_parameter(filter_node, "os_build", SOAP_STRINGARRAY, version);
|
||
|
+
|
||
|
+ soap_request_add_method_parameter(req, "page_number", SOAP_INTEGER, "1");
|
||
|
+ soap_request_add_method_parameter(req, "per_page", SOAP_INTEGER, /* -1 means get all issues */ "-1");
|
||
|
+
|
||
|
+ mantisbt_result_t *result = mantisbt_soap_call(settings, req);
|
||
|
+ soap_request_free(req);
|
||
|
+
|
||
|
+ if (result->mr_error == -1)
|
||
|
+ {
|
||
|
+ error_msg(_("Failed to search MantisBT duplicate issue: '%s'"), result->mr_msg);
|
||
|
+ mantisbt_result_free(result);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ GList *ids = response_get_main_ids_list(result->mr_body);
|
||
|
+
|
||
|
+ return ids;
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+custom_field_get_id_from_name(GList *ids, GList *names, const char *name)
|
||
|
+{
|
||
|
+ GList *i = ids;
|
||
|
+ GList *n = names;
|
||
|
+ for (; i != NULL; i = i->next, n = n->next)
|
||
|
+ {
|
||
|
+ if (strcmp(n->data, name) == 0)
|
||
|
+ return i->data;
|
||
|
+ }
|
||
|
+
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+custom_field_ask(const char *name)
|
||
|
+{
|
||
|
+ char *msg = xasprintf(_("CentOS Bug Tracker doesn't contain custom field '%s', which is required for full functionality of the reporter. Do you still want to create a new issue?"), name);
|
||
|
+ int yes = ask_yes_no(msg);
|
||
|
+ free(msg);
|
||
|
+
|
||
|
+ if (!yes)
|
||
|
+ {
|
||
|
+ set_xfunc_error_retval(EXIT_CANCEL_BY_USER);
|
||
|
+ xfunc_die();
|
||
|
+ }
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+mantisbt_get_custom_fields(const mantisbt_settings_t *settings, mantisbt_custom_fields_t *fields, const char *project_id)
|
||
|
+{
|
||
|
+ soap_request_t *req = soap_request_new_for_method("mc_project_get_custom_fields");
|
||
|
+ soap_request_add_credentials_parameter(req, settings);
|
||
|
+ soap_request_add_method_parameter(req, "project_id", SOAP_INTEGER, project_id);
|
||
|
+
|
||
|
+ mantisbt_result_t *result = mantisbt_soap_call(settings, req);
|
||
|
+ soap_request_free(req);
|
||
|
+
|
||
|
+ if (result->mr_http_resp_code != 200)
|
||
|
+ error_msg_and_die(_("Failed to get custom fields for '%s' project"), settings->m_project);
|
||
|
+
|
||
|
+ GList *ids = response_values_at_depth_by_name(result->mr_body, "id", -1);
|
||
|
+ GList *names = response_values_at_depth_by_name(result->mr_body, "name", -1);
|
||
|
+
|
||
|
+ mantisbt_result_free(result);
|
||
|
+
|
||
|
+ if ((fields->cf_abrt_hash_id = custom_field_get_id_from_name(ids, names, CUSTOMFIELD_DUPHASH)) == NULL)
|
||
|
+ custom_field_ask(CUSTOMFIELD_DUPHASH);
|
||
|
+
|
||
|
+ if ((fields->cf_url_id = custom_field_get_id_from_name(ids, names, CUSTOMFIELD_URL)) == NULL)
|
||
|
+ custom_field_ask(CUSTOMFIELD_URL);
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+mantisbt_create_new_issue(const mantisbt_settings_t *settings,
|
||
|
+ problem_data_t *problem_data,
|
||
|
+ const problem_report_t *pr,
|
||
|
+ const char *tracker_url)
|
||
|
+{
|
||
|
+
|
||
|
+ const char *category = problem_data_get_content_or_NULL(problem_data, FILENAME_COMPONENT);
|
||
|
+ const char *duphash = problem_data_get_content_or_NULL(problem_data, FILENAME_DUPHASH);
|
||
|
+
|
||
|
+ char *summary = shorten_string_to_length(problem_report_get_summary(pr), MAX_SUMMARY_LENGTH);
|
||
|
+
|
||
|
+ const char *description = problem_report_get_description(pr);
|
||
|
+ const char *additional_information = problem_report_get_section(pr, PR_SEC_ADDITIONAL_INFO);
|
||
|
+
|
||
|
+ mantisbt_custom_fields_t fields;
|
||
|
+ mantisbt_get_custom_fields(settings, &fields, settings->m_project_id);
|
||
|
+
|
||
|
+ soap_request_t *req = soap_request_new_for_method("mc_issue_add");
|
||
|
+ soap_request_add_credentials_parameter(req, settings);
|
||
|
+ soap_add_new_issue_parameters(req, settings->m_project, settings->m_project_version, category, summary, description, additional_information, settings->m_create_private, &fields, duphash, tracker_url);
|
||
|
+
|
||
|
+ mantisbt_result_t *result = mantisbt_soap_call(settings, req);
|
||
|
+ soap_request_free(req);
|
||
|
+ free(summary);
|
||
|
+
|
||
|
+ if (result->mr_error == -1)
|
||
|
+ {
|
||
|
+ error_msg(_("Failed to create a new issue: '%s'"), result->mr_msg);
|
||
|
+ mantisbt_result_free(result);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ int id = response_get_return_value(result->mr_body);
|
||
|
+
|
||
|
+ mantisbt_result_free(result);
|
||
|
+ return id;
|
||
|
+}
|
||
|
+
|
||
|
+mantisbt_issue_info_t *
|
||
|
+mantisbt_get_issue_info(const mantisbt_settings_t *settings, int issue_id)
|
||
|
+{
|
||
|
+ soap_request_t *req = soap_request_new_for_method("mc_issue_get");
|
||
|
+ soap_request_add_credentials_parameter(req, settings);
|
||
|
+
|
||
|
+ char *issue_id_str = xasprintf("%d", issue_id);
|
||
|
+ soap_request_add_method_parameter(req, "issue_id", SOAP_INTEGER, issue_id_str);
|
||
|
+ free(issue_id_str);
|
||
|
+
|
||
|
+ mantisbt_result_t *result = mantisbt_soap_call(settings, req);
|
||
|
+ soap_request_free(req);
|
||
|
+
|
||
|
+ if (result->mr_error == -1)
|
||
|
+ {
|
||
|
+ error_msg(_("Failed to get MantisBT issue: '%s'"), result->mr_msg);
|
||
|
+ mantisbt_result_free(result);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ mantisbt_issue_info_t *issue_info = mantisbt_issue_info_new();
|
||
|
+
|
||
|
+ issue_info->mii_id = issue_id;
|
||
|
+ issue_info->mii_status = response_get_name_value_of_element(result->mr_body, "status");
|
||
|
+ issue_info->mii_resolution = response_get_name_value_of_element(result->mr_body, "resolution");
|
||
|
+ issue_info->mii_reporter = response_get_name_value_of_element(result->mr_body, "reporter");
|
||
|
+ issue_info->mii_project = response_get_name_value_of_element(result->mr_body, "project");
|
||
|
+
|
||
|
+ if (strcmp(issue_info->mii_status, "closed") == 0 && !issue_info->mii_resolution)
|
||
|
+ error_msg(_("Issue %i is CLOSED, but it has no RESOLUTION"), issue_info->mii_id);
|
||
|
+
|
||
|
+ issue_info->mii_dup_id = response_get_id_of_relatedto_issue(result->mr_body);
|
||
|
+
|
||
|
+ if (strcmp(issue_info->mii_status, "closed") == 0
|
||
|
+ && strcmp(issue_info->mii_resolution, "duplicate") == 0
|
||
|
+ && issue_info->mii_dup_id == -1 )
|
||
|
+ {
|
||
|
+ error_msg(_("Issue %i is CLOSED as DUPLICATE, but it has no DUPLICATE_ID"),
|
||
|
+ issue_info->mii_id);
|
||
|
+ }
|
||
|
+
|
||
|
+ /* notes are stored in <text> element */
|
||
|
+ issue_info->mii_notes = response_values_at_depth_by_name(result->mr_body, "text", -1);
|
||
|
+
|
||
|
+ /* looking for bt rating in additional information too */
|
||
|
+ char *add_info = response_get_additioanl_information(result->mr_body);
|
||
|
+ if (add_info != NULL)
|
||
|
+ issue_info->mii_notes = g_list_append (issue_info->mii_notes, add_info);
|
||
|
+ issue_info->mii_attachments = response_values_at_depth_by_name(result->mr_body, "filename", -1);
|
||
|
+ issue_info->mii_best_bt_rating = comments_find_best_bt_rating(issue_info->mii_notes);
|
||
|
+
|
||
|
+ mantisbt_result_free(result);
|
||
|
+ return issue_info;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+mantisbt_add_issue_note(const mantisbt_settings_t *settings, int issue_id, const char *note)
|
||
|
+{
|
||
|
+ soap_request_t *req = soap_request_new_for_method("mc_issue_note_add");
|
||
|
+ soap_request_add_credentials_parameter(req, settings);
|
||
|
+
|
||
|
+ char *issue_id_str = xasprintf("%i", issue_id);
|
||
|
+ soap_node_add_child_node(req->sr_method, "issue_id", SOAP_INTEGER, issue_id_str);
|
||
|
+
|
||
|
+ xmlNodePtr note_node = soap_node_add_child_node(req->sr_method, "note", SOAP_ISSUENOTE, /* content */ NULL);
|
||
|
+ soap_node_add_child_node(note_node, "text", SOAP_STRING, note);
|
||
|
+
|
||
|
+ mantisbt_result_t *result = mantisbt_soap_call(settings, req);
|
||
|
+
|
||
|
+ free(issue_id_str);
|
||
|
+ soap_request_free(req);
|
||
|
+
|
||
|
+ if (result->mr_error == -1)
|
||
|
+ {
|
||
|
+ error_msg(_("Failed to add MantisBT issue note: '%s'"), result->mr_msg);
|
||
|
+ mantisbt_result_free(result);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ int id = response_get_return_value(result->mr_body);
|
||
|
+
|
||
|
+ mantisbt_result_free(result);
|
||
|
+ return id;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+mantisbt_get_project_id_from_name(mantisbt_settings_t *settings)
|
||
|
+{
|
||
|
+ if (settings->m_project == NULL)
|
||
|
+ error_msg_and_die(_("The MantisBT project has not been deretmined."));
|
||
|
+
|
||
|
+ soap_request_t *req = soap_request_new_for_method("mc_project_get_id_from_name");
|
||
|
+ soap_request_add_credentials_parameter(req, settings);
|
||
|
+ soap_node_add_child_node(req->sr_method, "project_name", SOAP_STRING, settings->m_project);
|
||
|
+
|
||
|
+ mantisbt_result_t *result = mantisbt_soap_call(settings, req);
|
||
|
+
|
||
|
+ if (result->mr_http_resp_code != 200)
|
||
|
+ error_msg_and_die(_("Failed to get project id from name"));
|
||
|
+
|
||
|
+ settings->m_project_id = response_get_return_value_as_string(result->mr_body);
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
diff --git a/src/plugins/mantisbt.conf b/src/plugins/mantisbt.conf
|
||
|
new file mode 100644
|
||
|
index 0000000..15a1065
|
||
|
--- /dev/null
|
||
|
+++ b/src/plugins/mantisbt.conf
|
||
|
@@ -0,0 +1,8 @@
|
||
|
+# MantisBT URL
|
||
|
+MantisbtURL = https://bugs.centos.org/
|
||
|
+# yes means that ssl certificates will be checked
|
||
|
+SSLVerify = yes
|
||
|
+# your login has to exist, if you don have any, please create one
|
||
|
+Login =
|
||
|
+# your password
|
||
|
+Password =
|
||
|
diff --git a/src/plugins/mantisbt.h b/src/plugins/mantisbt.h
|
||
|
new file mode 100644
|
||
|
index 0000000..c31c174
|
||
|
--- /dev/null
|
||
|
+++ b/src/plugins/mantisbt.h
|
||
|
@@ -0,0 +1,140 @@
|
||
|
+/*
|
||
|
+ Copyright (C) 2014 ABRT team
|
||
|
+ Copyright (C) 2014 RedHat Inc
|
||
|
+
|
||
|
+ 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 2 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, write to the Free Software Foundation, Inc.,
|
||
|
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
+*/
|
||
|
+
|
||
|
+#ifndef MANTISBT_H
|
||
|
+#define MANTISBT_H
|
||
|
+
|
||
|
+#ifdef __cplusplus
|
||
|
+extern "C" {
|
||
|
+#endif
|
||
|
+
|
||
|
+#include <libxml/encoding.h>
|
||
|
+#include "problem_report.h"
|
||
|
+
|
||
|
+#define SOAP_STRING "ns2:string"
|
||
|
+#define SOAP_INTEGER "ns2:integer"
|
||
|
+#define SOAP_INTEGERARRAY "ns2:IntegerArray"
|
||
|
+#define SOAP_STRINGARRAY "ns2:StringArray"
|
||
|
+#define SOAP_ISSUEDATA "ns3:IssueData"
|
||
|
+#define SOAP_OBJECTREF "ns3:ObjectRef"
|
||
|
+#define SOAP_CUSTOMFIELD_ARRAY "ns2:CustomFieldValueForIssueDataArray"
|
||
|
+#define SOAP_FILTER_CUSTOMFIELD "ns2:FilterCustomField"
|
||
|
+#define SOAP_FILTER_CUSTOMFIELD_ARRAY "ns2:FilterCustomFieldArray"
|
||
|
+#define SOAP_FILTER_SEARCH_DATA "ns2:FilterSearchData"
|
||
|
+#define SOAP_CUSTOMFIELD "ns2:CustomFieldValueForIssueData"
|
||
|
+#define SOAP_BASE64 "SOAP-ENC:base64"
|
||
|
+#define SOAP_ISSUENOTE "ns3:IssueNoteData"
|
||
|
+
|
||
|
+#define PR_SEC_ADDITIONAL_INFO "Additional info"
|
||
|
+
|
||
|
+typedef struct soap_request
|
||
|
+{
|
||
|
+ xmlNodePtr sr_root;
|
||
|
+ xmlNodePtr sr_body;
|
||
|
+ xmlNodePtr sr_method;
|
||
|
+} soap_request_t;
|
||
|
+
|
||
|
+typedef struct mantisbt_settings
|
||
|
+{
|
||
|
+ char *m_login;
|
||
|
+ char *m_password;
|
||
|
+ const char *m_mantisbt_url;
|
||
|
+ const char *m_mantisbt_soap_url;
|
||
|
+ char *m_project;
|
||
|
+ char *m_project_id;
|
||
|
+ char *m_project_version;
|
||
|
+ const char *m_DontMatchComponents;
|
||
|
+ int m_ssl_verify;
|
||
|
+ int m_create_private;
|
||
|
+} mantisbt_settings_t;
|
||
|
+
|
||
|
+typedef struct mantisbt_result
|
||
|
+{
|
||
|
+ int mr_http_resp_code;
|
||
|
+ int mr_error;
|
||
|
+ char *mr_msg;
|
||
|
+ char *mr_url;
|
||
|
+ char *mr_body;
|
||
|
+} mantisbt_result_t;
|
||
|
+
|
||
|
+typedef struct mantisbt_issue_info
|
||
|
+{
|
||
|
+ int mii_id;
|
||
|
+ int mii_dup_id;
|
||
|
+ unsigned mii_best_bt_rating;
|
||
|
+
|
||
|
+ char *mii_status;
|
||
|
+ char *mii_resolution;
|
||
|
+ char *mii_reporter;
|
||
|
+ char *mii_project;
|
||
|
+
|
||
|
+ GList *mii_notes;
|
||
|
+ GList *mii_attachments;
|
||
|
+} mantisbt_issue_info_t;
|
||
|
+
|
||
|
+void mantisbt_settings_free(mantisbt_settings_t *settings);
|
||
|
+
|
||
|
+mantisbt_issue_info_t * mantisbt_issue_info_new();
|
||
|
+void mantisbt_issue_info_free(mantisbt_issue_info_t *info);
|
||
|
+mantisbt_issue_info_t * mantisbt_find_origin_bug_closed_duplicate(mantisbt_settings_t *settings, mantisbt_issue_info_t *info);
|
||
|
+
|
||
|
+void soap_request_free(soap_request_t *req);
|
||
|
+
|
||
|
+soap_request_t *soap_request_new_for_method(const char *method);
|
||
|
+
|
||
|
+void soap_request_add_method_parameter(soap_request_t *req, const char *name, const char *type, const char *value);
|
||
|
+void soap_request_add_credentials_parameter(soap_request_t *req, const mantisbt_settings_t *settings);
|
||
|
+
|
||
|
+char *soap_request_to_str(const soap_request_t *req);
|
||
|
+
|
||
|
+#if 0
|
||
|
+void soap_request_print(soap_request_t *req);
|
||
|
+#endif
|
||
|
+
|
||
|
+GList * response_get_main_ids_list(const char *xml);
|
||
|
+int response_get_main_id(const char *xml);
|
||
|
+void response_values_free(GList *values);
|
||
|
+
|
||
|
+void mantisbt_result_free(mantisbt_result_t *result);
|
||
|
+mantisbt_result_t *mantisbt_soap_call(const mantisbt_settings_t *settings, const soap_request_t *req);
|
||
|
+
|
||
|
+int mantisbt_attach_data(const mantisbt_settings_t *settings, const char *bug_id,
|
||
|
+ const char *att_name, const char *data, int size);
|
||
|
+
|
||
|
+int mantisbt_attach_file(const mantisbt_settings_t *settings, const char *bug_id,
|
||
|
+ const char *att_name, const char *data);
|
||
|
+
|
||
|
+GList * mantisbt_search_by_abrt_hash(mantisbt_settings_t *settings, const char *abrt_hash);
|
||
|
+GList * mantisbt_search_duplicate_issues(mantisbt_settings_t *settings, const char *category,
|
||
|
+ const char *version, const char *abrt_hash);
|
||
|
+
|
||
|
+int mantisbt_create_new_issue(const mantisbt_settings_t *settings, problem_data_t *problem_data,
|
||
|
+ const problem_report_t *pr, const char *tracker_url);
|
||
|
+
|
||
|
+mantisbt_issue_info_t * mantisbt_get_issue_info(const mantisbt_settings_t *settings, int issue_id);
|
||
|
+int mantisbt_add_issue_note(const mantisbt_settings_t *settings, int issue_id, const char *note);
|
||
|
+
|
||
|
+void mantisbt_get_project_id_from_name(mantisbt_settings_t *settings);
|
||
|
+
|
||
|
+#ifdef __cplusplus
|
||
|
+}
|
||
|
+#endif
|
||
|
+
|
||
|
+#endif
|
||
|
+
|
||
|
diff --git a/src/plugins/mantisbt_format.conf b/src/plugins/mantisbt_format.conf
|
||
|
new file mode 100644
|
||
|
index 0000000..da08aa6
|
||
|
--- /dev/null
|
||
|
+++ b/src/plugins/mantisbt_format.conf
|
||
|
@@ -0,0 +1,59 @@
|
||
|
+# Lines starting with # are ignored.
|
||
|
+# Lines can be continued on the next line using trailing backslash.
|
||
|
+#
|
||
|
+# Format:
|
||
|
+# %summary:: summary format
|
||
|
+# section:: element1[,element2]...
|
||
|
+# The literal text line to be added to Bugzilla comment. Can be empty.
|
||
|
+# (IOW: empty lines are NOT ignored!)
|
||
|
+#
|
||
|
+# Summary format is a line of text, where %element% is replaced by
|
||
|
+# text element's content, and [[...%element%...]] block is used only if
|
||
|
+# %element% exists. [[...]] blocks can nest.
|
||
|
+#
|
||
|
+# Sections can be:
|
||
|
+# - %summary: bug summary format string.
|
||
|
+# - %attach: a list of elements to attach.
|
||
|
+# - text, double colon (::) and the list of comma-separated elements.
|
||
|
+# Text can be empty (":: elem1, elem2, elem3" works),
|
||
|
+# in this case "Text:" header line will be omitted.
|
||
|
+#
|
||
|
+# Elements can be:
|
||
|
+# - problem directory element names, which get formatted as
|
||
|
+# <element_name>: <contents>
|
||
|
+# or
|
||
|
+# <element_name>:
|
||
|
+# :<contents>
|
||
|
+# :<contents>
|
||
|
+# :<contents>
|
||
|
+# - problem directory element names prefixed by "%bare_",
|
||
|
+# which is formatted as-is, without "<element_name>:" and colons
|
||
|
+# - %oneline, %multiline, %text wildcards, which select all corresponding
|
||
|
+# elements for output or attachment
|
||
|
+# - %binary wildcard, valid only for %attach section, instructs to attach
|
||
|
+# binary elements
|
||
|
+# - problem directory element names prefixed by "-",
|
||
|
+# which excludes given element from all wildcards
|
||
|
+#
|
||
|
+# Nonexistent elements are silently ignored.
|
||
|
+# If none of elements exists, the section will not be created.
|
||
|
+
|
||
|
+%summary:: [abrt] %pkg_name%[[: %crash_function%()]][[: %reason%]][[: TAINTED %tainted_short%]]
|
||
|
+
|
||
|
+Description of problem:: %bare_comment
|
||
|
+
|
||
|
+Version-Release number of selected component:: %bare_package
|
||
|
+
|
||
|
+Truncated backtrace:: %bare_%short_backtrace
|
||
|
+
|
||
|
+%Additional info::
|
||
|
+:: -pkg_arch,-pkg_epoch,-pkg_name,-pkg_release,-pkg_version,\
|
||
|
+ -component,-architecture,\
|
||
|
+ -analyzer,-count,-duphash,-uuid,-abrt_version,\
|
||
|
+ -username,-hostname,-os_release,-os_info,\
|
||
|
+ -time,-pid,-pwd,-last_occurrence,-ureports_counter,\
|
||
|
+ %reporter,\
|
||
|
+ %oneline
|
||
|
+
|
||
|
+%attach:: -comment,-reason,-reported_to,-event_log,%multiline,\
|
||
|
+ -coredump,%binary
|
||
|
diff --git a/src/plugins/mantisbt_formatdup.conf b/src/plugins/mantisbt_formatdup.conf
|
||
|
new file mode 100644
|
||
|
index 0000000..b1552ac
|
||
|
--- /dev/null
|
||
|
+++ b/src/plugins/mantisbt_formatdup.conf
|
||
|
@@ -0,0 +1,65 @@
|
||
|
+# Lines starting with # are ignored.
|
||
|
+# Lines can be continued on the next line using trailing backslash.
|
||
|
+#
|
||
|
+# Format:
|
||
|
+# %summary:: summary format
|
||
|
+# section:: element1[,element2]...
|
||
|
+# The literal text line to be added to Bugzilla comment. Can be empty.
|
||
|
+# (IOW: empty lines are NOT ignored!)
|
||
|
+#
|
||
|
+# Summary format is a line of text, where %element% is replaced by
|
||
|
+# text element's content, and [[...%element%...]] block is used only if
|
||
|
+# %element% exists. [[...]] blocks can nest.
|
||
|
+#
|
||
|
+# Sections can be:
|
||
|
+# - %summary: bug summary format string.
|
||
|
+# - %attach: a list of elements to attach.
|
||
|
+# - text, double colon (::) and the list of comma-separated elements.
|
||
|
+# Text can be empty (":: elem1, elem2, elem3" works),
|
||
|
+# in this case "Text:" header line will be omitted.
|
||
|
+#
|
||
|
+# Elements can be:
|
||
|
+# - problem directory element names, which get formatted as
|
||
|
+# <element_name>: <contents>
|
||
|
+# or
|
||
|
+# <element_name>:
|
||
|
+# :<contents>
|
||
|
+# :<contents>
|
||
|
+# :<contents>
|
||
|
+# - problem directory element names prefixed by "%bare_",
|
||
|
+# which is formatted as-is, without "<element_name>:" and colons
|
||
|
+# - %oneline, %multiline, %text wildcards, which select all corresponding
|
||
|
+# elements for output or attachment
|
||
|
+# - %binary wildcard, valid only for %attach section, instructs to attach
|
||
|
+# binary elements
|
||
|
+# - problem directory element names prefixed by "-",
|
||
|
+# which excludes given element from all wildcards
|
||
|
+#
|
||
|
+# Nonexistent elements are silently ignored.
|
||
|
+# If none of elements exists, the section will not be created.
|
||
|
+
|
||
|
+# When we add a comment to an existing BZ, %summary is ignored
|
||
|
+# (it specifies *new bug* summary field):
|
||
|
+# %summary:: blah blah
|
||
|
+
|
||
|
+# When dup is detected, BZ reporter adds a comment to it.
|
||
|
+# This comment may interrupt an ongoing conversation in the BZ.
|
||
|
+# (Three people independently filed a bug against abrt about this).
|
||
|
+# Need to clearly explain what this comment is, to prevent confusion.
|
||
|
+# Hopefully, this line would suffice:
|
||
|
+Another user experienced a similar problem:
|
||
|
+
|
||
|
+# If user filled out comment field, show it:
|
||
|
+:: %bare_comment
|
||
|
+
|
||
|
+# var_log_messages has too much variance (time/date),
|
||
|
+# we exclude it from message so that dup message elimination has more chances to work
|
||
|
+:: \
|
||
|
+ -pkg_arch,-pkg_epoch,-pkg_name,-pkg_release,-pkg_version,\
|
||
|
+ -component,-architecture,\
|
||
|
+ -analyzer,-count,-duphash,-uuid,-abrt_version,\
|
||
|
+ -username,-hostname,-os_release,-os_info,\
|
||
|
+ -time,-pid,-pwd,-last_occurrence,-ureports_counter,\
|
||
|
+ -var_log_messages,\
|
||
|
+ %reporter,\
|
||
|
+ %oneline
|
||
|
diff --git a/src/plugins/report_CentOSBugTracker.conf b/src/plugins/report_CentOSBugTracker.conf
|
||
|
new file mode 100644
|
||
|
index 0000000..04cab13
|
||
|
--- /dev/null
|
||
|
+++ b/src/plugins/report_CentOSBugTracker.conf
|
||
|
@@ -0,0 +1,4 @@
|
||
|
+Mantisbt_MantisbtURL = https://bugs.centos.org
|
||
|
+Mantisbt_Login =
|
||
|
+Mantisbt_Password
|
||
|
+Mantisbt_SSLVerify = yes
|
||
|
diff --git a/src/plugins/report_CentOSBugTracker.xml.in b/src/plugins/report_CentOSBugTracker.xml.in
|
||
|
new file mode 100644
|
||
|
index 0000000..81f909b
|
||
|
--- /dev/null
|
||
|
+++ b/src/plugins/report_CentOSBugTracker.xml.in
|
||
|
@@ -0,0 +1,65 @@
|
||
|
+<?xml version="1.0" encoding="UTF-8" ?>
|
||
|
+<event>
|
||
|
+ <_name>CentOS Bug Tracker</_name>
|
||
|
+ <_description>Report to CentOS Bug Tracker</_description>
|
||
|
+
|
||
|
+ <requires-items>component,duphash,os_release</requires-items>
|
||
|
+ <exclude-items-by-default>coredump,count,event_log,reported_to,vmcore</exclude-items-by-default>
|
||
|
+ <exclude-items-always></exclude-items-always>
|
||
|
+ <exclude-binary-items>no</exclude-binary-items>
|
||
|
+ <include-items-by-default></include-items-by-default>
|
||
|
+ <minimal-rating>3</minimal-rating>
|
||
|
+ <gui-review-elements>yes</gui-review-elements>
|
||
|
+
|
||
|
+ <options>
|
||
|
+ <option type="text" name="Mantisbt_Login">
|
||
|
+ <_label>User name</_label>
|
||
|
+ <allow-empty>no</allow-empty>
|
||
|
+ <_description>CentOS Bug Tracker account user name</_description>
|
||
|
+ <_note-html>You can create bugs.centos.org account <a href="https://bugs.centos.org/signup_page.php">here</a></_note-html>
|
||
|
+ </option>
|
||
|
+ <option type="password" name="Mantisbt_Password">
|
||
|
+ <_label>Password</_label>
|
||
|
+ <allow-empty>no</allow-empty>
|
||
|
+ <_description>CentOS Bug Tracker account password</_description>
|
||
|
+ </option>
|
||
|
+ <advanced-options>
|
||
|
+ <option type="text" name="Mantisbt_MantisbtURL">
|
||
|
+ <_label>CentOS Bug Tracker URL</_label>
|
||
|
+ <allow-empty>no</allow-empty>
|
||
|
+ <_note-html>Address of CentOS Bug Tracker server</_note-html>
|
||
|
+ <default-value>https://bugs.centos.org</default-value>
|
||
|
+ </option>
|
||
|
+ <option type="bool" name="Mantisbt_SSLVerify">
|
||
|
+ <_label>Verify SSL</_label>
|
||
|
+ <_note-html>Check SSL key validity</_note-html>
|
||
|
+ <default-value>yes</default-value>
|
||
|
+ </option>
|
||
|
+ <option type="text" name="Mantisbt_Project">
|
||
|
+ <_label>CentOS Bug Tracker project</_label>
|
||
|
+ <allow-empty>yes</allow-empty>
|
||
|
+ <_note-html>Specify this only if you needed different project than specified in /etc/os-release</_note-html>
|
||
|
+ </option>
|
||
|
+ <option type="text" name="Mantisbt_ProjectVersion">
|
||
|
+ <_label>CentOS Bug Tracker project version</_label>
|
||
|
+ <allow-empty>yes</allow-empty>
|
||
|
+ <_note-html>Specify this only if you needed different project version than specified in /etc/os-release</_note-html>
|
||
|
+ </option>
|
||
|
+ <option type="text" name="http_proxy">
|
||
|
+ <_label>HTTP Proxy</_label>
|
||
|
+ <allow-empty>yes</allow-empty>
|
||
|
+ <_note-html>Sets the proxy server to use for HTTP</_note-html>
|
||
|
+ </option>
|
||
|
+ <option type="text" name="HTTPS_PROXY">
|
||
|
+ <_label>HTTPS Proxy</_label>
|
||
|
+ <allow-empty>yes</allow-empty>
|
||
|
+ <_note-html>Sets the proxy server to use for HTTPS</_note-html>
|
||
|
+ </option>
|
||
|
+ <option type="bool" name="Mantisbt_CreatePrivate">
|
||
|
+ <_label>Restrict access</_label>
|
||
|
+ <_note-html>Restrict access to the created CentOS Bug Tracker issue allowing only users from specified groups to view it (see advanced settings for more details)</_note-html>
|
||
|
+ <default-value>no</default-value>
|
||
|
+ </option>
|
||
|
+ </advanced-options>
|
||
|
+ </options>
|
||
|
+</event>
|
||
|
diff --git a/src/plugins/reporter-mantisbt.c b/src/plugins/reporter-mantisbt.c
|
||
|
new file mode 100644
|
||
|
index 0000000..d281cdb
|
||
|
--- /dev/null
|
||
|
+++ b/src/plugins/reporter-mantisbt.c
|
||
|
@@ -0,0 +1,696 @@
|
||
|
+/*
|
||
|
+ Copyright (C) 2014 ABRT team
|
||
|
+ Copyright (C) 2014 RedHat Inc
|
||
|
+
|
||
|
+ 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 2 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, write to the Free Software Foundation, Inc., 51
|
||
|
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
+*/
|
||
|
+
|
||
|
+#include "internal_libreport.h"
|
||
|
+#include "client.h"
|
||
|
+#include "mantisbt.h"
|
||
|
+#include "problem_report.h"
|
||
|
+
|
||
|
+static void
|
||
|
+parse_osinfo_for_mantisbt(map_string_t *osinfo, char** project, char** version)
|
||
|
+{
|
||
|
+ const char *name = get_map_string_item_or_NULL(osinfo, "CENTOS_MANTISBT_PROJECT");
|
||
|
+ if (!name)
|
||
|
+ name = get_map_string_item_or_NULL(osinfo, OSINFO_NAME);
|
||
|
+
|
||
|
+ const char *version_id = get_map_string_item_or_NULL(osinfo, "CENTOS_MANTISBT_PROJECT_VERSION");
|
||
|
+ if (!version_id)
|
||
|
+ version_id = get_map_string_item_or_NULL(osinfo, OSINFO_VERSION_ID);
|
||
|
+
|
||
|
+ if (name && version_id)
|
||
|
+ {
|
||
|
+ *project = xstrdup(name);
|
||
|
+ *version = xstrdup(version_id);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* something bad happend */
|
||
|
+ *project = NULL;
|
||
|
+ *version = NULL;
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+ask_mantisbt_login(const char *message)
|
||
|
+{
|
||
|
+ char *login = ask(message);
|
||
|
+ if (login == NULL || login[0] == '\0')
|
||
|
+ {
|
||
|
+ set_xfunc_error_retval(EXIT_CANCEL_BY_USER);
|
||
|
+ error_msg_and_die(_("Can't continue without login"));
|
||
|
+ }
|
||
|
+
|
||
|
+ return login;
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+ask_mantisbt_password(const char *message)
|
||
|
+{
|
||
|
+ char *password = ask_password(message);
|
||
|
+ /* TODO: this should be fixed in ask_password() as other tools have the same problem */
|
||
|
+ putchar('\n');
|
||
|
+ if (password == NULL || password[0] == '\0')
|
||
|
+ {
|
||
|
+ set_xfunc_error_retval(EXIT_CANCEL_BY_USER);
|
||
|
+ error_msg_and_die(_("Can't continue without password"));
|
||
|
+ }
|
||
|
+
|
||
|
+ return password;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+ask_mantisbt_credentials(mantisbt_settings_t *settings, const char *pre_message)
|
||
|
+{
|
||
|
+ free(settings->m_login);
|
||
|
+ free(settings->m_password);
|
||
|
+
|
||
|
+ char *question = xasprintf("%s %s", pre_message, _("Please enter your CentOS Bug Tracker login:"));
|
||
|
+ settings->m_login = ask_mantisbt_login(question);
|
||
|
+ free(question);
|
||
|
+
|
||
|
+ question = xasprintf("%s %s '%s':", pre_message, _("Please enter the password for"), settings->m_login);
|
||
|
+ settings->m_password = ask_mantisbt_password(question);
|
||
|
+ free(question);
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+verify_credentials(mantisbt_settings_t *settings)
|
||
|
+{
|
||
|
+ if (settings->m_login[0] == '\0' || settings->m_password[0] == '\0')
|
||
|
+ ask_mantisbt_credentials(settings, _("Credentials are not provided by configuration."));
|
||
|
+
|
||
|
+ while (true)
|
||
|
+ {
|
||
|
+ soap_request_t *req = soap_request_new_for_method("mc_login");
|
||
|
+ soap_request_add_credentials_parameter(req, settings);
|
||
|
+
|
||
|
+ mantisbt_result_t *result = mantisbt_soap_call(settings, req);
|
||
|
+ soap_request_free(req);
|
||
|
+
|
||
|
+ if (g_verbose > 2)
|
||
|
+ {
|
||
|
+ GList *ids = response_get_main_ids_list(result->mr_body);
|
||
|
+ if (ids != NULL)
|
||
|
+ log("%s", (char *)ids->data);
|
||
|
+ response_values_free(ids);
|
||
|
+ }
|
||
|
+
|
||
|
+ int result_val = result->mr_http_resp_code;
|
||
|
+ mantisbt_result_free(result);
|
||
|
+
|
||
|
+ if (result_val == 200)
|
||
|
+ return;
|
||
|
+
|
||
|
+ ask_mantisbt_credentials(settings, _("Invalid password or login."));
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+set_settings(mantisbt_settings_t *m, map_string_t *settings, struct dump_dir *dd)
|
||
|
+{
|
||
|
+ const char *environ;
|
||
|
+
|
||
|
+ environ = getenv("Mantisbt_Login");
|
||
|
+ m->m_login = xstrdup(environ ? environ : get_map_string_item_or_empty(settings, "Login"));
|
||
|
+
|
||
|
+ environ = getenv("Mantisbt_Password");
|
||
|
+ m->m_password = xstrdup(environ ? environ : get_map_string_item_or_empty(settings, "Password"));
|
||
|
+
|
||
|
+ environ = getenv("Mantisbt_MantisbtURL");
|
||
|
+ m->m_mantisbt_url = environ ? environ : get_map_string_item_or_empty(settings, "MantisbtURL");
|
||
|
+ if (!m->m_mantisbt_url[0])
|
||
|
+ m->m_mantisbt_url = "https://bugs.centos.org/";
|
||
|
+ else
|
||
|
+ {
|
||
|
+ /* We don't want trailing '/': "https://host/dir/" -> "https://host/dir" */
|
||
|
+ char *last_slash = strrchr(m->m_mantisbt_url, '/');
|
||
|
+ if (last_slash && last_slash[1] == '\0')
|
||
|
+ *last_slash = '\0';
|
||
|
+ }
|
||
|
+ m->m_mantisbt_soap_url = concat_path_file(m->m_mantisbt_url, "api/soap/mantisconnect.php");
|
||
|
+
|
||
|
+ environ = getenv("Mantisbt_Project");
|
||
|
+ if (environ)
|
||
|
+ {
|
||
|
+ m->m_project = xstrdup(environ);
|
||
|
+ environ = getenv("Mantisbt_ProjectVersion");
|
||
|
+ if (environ)
|
||
|
+ m->m_project_version = xstrdup(environ);
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ const char *option = get_map_string_item_or_NULL(settings, "Project");
|
||
|
+ if (option)
|
||
|
+ m->m_project = xstrdup(option);
|
||
|
+ option = get_map_string_item_or_NULL(settings, "ProjectVersion");
|
||
|
+ if (option)
|
||
|
+ m->m_project_version = xstrdup(option);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!m->m_project || !*m->m_project) /* if not overridden or empty... */
|
||
|
+ {
|
||
|
+ free(m->m_project);
|
||
|
+ free(m->m_project_version);
|
||
|
+
|
||
|
+ if (dd != NULL)
|
||
|
+ {
|
||
|
+ map_string_t *osinfo = new_map_string();
|
||
|
+
|
||
|
+ char *os_info_data = dd_load_text(dd, FILENAME_OS_INFO);
|
||
|
+ parse_osinfo(os_info_data, osinfo);
|
||
|
+ free(os_info_data);
|
||
|
+
|
||
|
+ parse_osinfo_for_mantisbt(osinfo, &m->m_project, &m->m_project_version);
|
||
|
+ free_map_string(osinfo);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ environ = getenv("Mantisbt_SSLVerify");
|
||
|
+ m->m_ssl_verify = string_to_bool(environ ? environ : get_map_string_item_or_empty(settings, "SSLVerify"));
|
||
|
+
|
||
|
+ environ = getenv("Mantisbt_DontMatchComponents");
|
||
|
+ m->m_DontMatchComponents = environ ? environ : get_map_string_item_or_empty(settings, "DontMatchComponents");
|
||
|
+
|
||
|
+ environ = getenv(CREATE_PRIVATE_TICKET);
|
||
|
+ if (environ)
|
||
|
+ m->m_create_private = string_to_bool(environ);
|
||
|
+
|
||
|
+ if (!m->m_create_private)
|
||
|
+ {
|
||
|
+ environ = getenv("Mantisbt_CreatePrivate");
|
||
|
+ m->m_create_private = string_to_bool(environ ? environ : get_map_string_item_or_empty(settings, "CreatePrivate"));
|
||
|
+ }
|
||
|
+ log_notice("create private CentOS Bug Tracker ticket: '%s'", m->m_create_private ? "YES": "NO");
|
||
|
+}
|
||
|
+
|
||
|
+int main(int argc, char **argv)
|
||
|
+{
|
||
|
+ abrt_init(argv);
|
||
|
+
|
||
|
+ /* I18n */
|
||
|
+ setlocale(LC_ALL, "");
|
||
|
+#if ENABLE_NLS
|
||
|
+ bindtextdomain(PACKAGE, LOCALEDIR);
|
||
|
+ textdomain(PACKAGE);
|
||
|
+#endif
|
||
|
+
|
||
|
+ const char *program_usage_string = _(
|
||
|
+ "\n& [-vf] [-c CONFFILE]... [-F FMTFILE] [-A FMTFILE2] -d DIR"
|
||
|
+ "\nor:"
|
||
|
+ "\n& [-v] [-c CONFFILE]... [-d DIR] -t[ID] FILE..."
|
||
|
+ "\nor:"
|
||
|
+ "\n& [-v] [-c CONFFILE]... [-d DIR] -t[ID] -w"
|
||
|
+ "\nor:"
|
||
|
+ "\n& [-v] [-c CONFFILE]... -h DUPHASH"
|
||
|
+ "\n"
|
||
|
+ "\nReports problem to CentOS Bug Tracker."
|
||
|
+ "\n"
|
||
|
+ "\nThe tool reads DIR. Then it tries to find an issue"
|
||
|
+ "\nwith the same abrt_hash in custom field 'abrt_hash'."
|
||
|
+ "\n"
|
||
|
+ "\nIf such issue is not found, then a new issue is created. Elements of DIR"
|
||
|
+ "\nare stored in the issue as part of issue description or as attachments,"
|
||
|
+ "\ndepending on their type and size."
|
||
|
+ "\n"
|
||
|
+ "\nOtherwise, if such issue is found and it is marked as CLOSED DUPLICATE,"
|
||
|
+ "\nthe tool follows the chain of duplicates until it finds a non-DUPLICATE issue."
|
||
|
+ "\nThe tool adds a new comment to found issue."
|
||
|
+ "\n"
|
||
|
+ "\nThe URL to new or modified issue is printed to stdout and recorded in"
|
||
|
+ "\n'reported_to' element."
|
||
|
+ "\n"
|
||
|
+ "\nOption -t uploads FILEs to the already created issue on CentOS Bug Tracker site."
|
||
|
+ "\nThe issue ID is retrieved from directory specified by -d DIR."
|
||
|
+ "\nIf problem data in DIR was never reported to CentOS Bug Tracker, upload will fail."
|
||
|
+ "\n"
|
||
|
+ "\nOption -tID uploads FILEs to the issue with specified ID on CentOS Bug Tracker site."
|
||
|
+ "\n-d DIR is ignored."
|
||
|
+ "\n"
|
||
|
+ "\nOption -r sets the last url from reporter_to element which is prefixed with"
|
||
|
+ "\nTRACKER_NAME to URL field. This option is applied only when a new issue is to be"
|
||
|
+ "\nfiled. The default value is 'ABRT Server'"
|
||
|
+ "\n"
|
||
|
+ "\nIf not specified, CONFFILE defaults to "CONF_DIR"/plugins/mantisb.conf"
|
||
|
+ "\nIts lines should have 'PARAM = VALUE' format."
|
||
|
+ "\nRecognized string parameters: MantisbtURL, Login, Password, Project, ProjectVersion."
|
||
|
+ "\nRecognized boolean parameter (VALUE should be 1/0, yes/no): SSLVerify, CreatePrivate."
|
||
|
+ "\nParameters can be overridden via $Mantisbt_PARAM environment variables."
|
||
|
+ "\n"
|
||
|
+ "\nFMTFILE and FMTFILE2 default to "CONF_DIR"/plugins/mantisbt_format.conf"
|
||
|
+ );
|
||
|
+
|
||
|
+ enum {
|
||
|
+ OPT_v = 1 << 0,
|
||
|
+ OPT_d = 1 << 1,
|
||
|
+ OPT_c = 1 << 2,
|
||
|
+ OPT_F = 1 << 3,
|
||
|
+ OPT_A = 1 << 4,
|
||
|
+ OPT_t = 1 << 5,
|
||
|
+ OPT_f = 1 << 6,
|
||
|
+ OPT_h = 1 << 7,
|
||
|
+ OPT_r = 1 << 8,
|
||
|
+ OPT_D = 1 << 9,
|
||
|
+ };
|
||
|
+
|
||
|
+ const char *dump_dir_name = ".";
|
||
|
+ GList *conf_file = NULL;
|
||
|
+ const char *fmt_file = CONF_DIR"/plugins/mantisbt_format.conf";
|
||
|
+ const char *fmt_file2 = fmt_file;
|
||
|
+ char *abrt_hash = NULL;
|
||
|
+ char *ticket_no = NULL;
|
||
|
+ const char *tracker_str = "ABRT Server";
|
||
|
+ char *debug_str = NULL;
|
||
|
+ mantisbt_settings_t mbt_settings = { 0 };
|
||
|
+ /* Keep enum above and order of options below in sync! */
|
||
|
+ struct options program_options[] = {
|
||
|
+ OPT__VERBOSE(&g_verbose),
|
||
|
+ OPT_STRING( 'd', NULL, &dump_dir_name , "DIR" , _("Problem directory")),
|
||
|
+ OPT_LIST( 'c', NULL, &conf_file , "FILE" , _("Configuration file (may be given many times)")),
|
||
|
+ OPT_STRING( 'F', NULL, &fmt_file , "FILE" , _("Formatting file for initial comment")),
|
||
|
+ OPT_STRING( 'A', NULL, &fmt_file2 , "FILE" , _("Formatting file for duplicates")),
|
||
|
+ OPT_OPTSTRING('t', "ticket", &ticket_no , "ID" , _("Attach FILEs [to issue with this ID]")),
|
||
|
+ OPT_BOOL( 'f', NULL, NULL, _("Force reporting even if this problem is already reported")),
|
||
|
+ OPT_STRING( 'h', "duphash", &abrt_hash, "DUPHASH", _("Print BUG_ID which has given DUPHASH")),
|
||
|
+ OPT_STRING( 'r', "tracker", &tracker_str, "TRACKER_NAME", _("A name of bug tracker for an additional URL from 'reported_to'")),
|
||
|
+
|
||
|
+ OPT_OPTSTRING('D', "debug", &debug_str , "STR" , _("Debug")),
|
||
|
+ OPT_END()
|
||
|
+ };
|
||
|
+
|
||
|
+ unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
|
||
|
+ argv += optind;
|
||
|
+
|
||
|
+ export_abrt_envvars(0);
|
||
|
+
|
||
|
+ map_string_t *settings = new_map_string();
|
||
|
+
|
||
|
+ {
|
||
|
+ if (!conf_file)
|
||
|
+ conf_file = g_list_append(conf_file, (char*) CONF_DIR"/plugins/mantisbt.conf");
|
||
|
+ while (conf_file)
|
||
|
+ {
|
||
|
+ char *fn = (char *)conf_file->data;
|
||
|
+ log_notice("Loading settings from '%s'", fn);
|
||
|
+ load_conf_file(fn, settings, /*skip key w/o values:*/ false);
|
||
|
+ log_debug("Loaded '%s'", fn);
|
||
|
+ conf_file = g_list_delete_link(conf_file, conf_file);
|
||
|
+ }
|
||
|
+
|
||
|
+ struct dump_dir *dd = NULL;
|
||
|
+ if (abrt_hash == NULL)
|
||
|
+ {
|
||
|
+ dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
|
||
|
+ if (!dd)
|
||
|
+ error_msg_and_die(_("Can't open problem dir '%s'."), dump_dir_name);
|
||
|
+ }
|
||
|
+
|
||
|
+ set_settings(&mbt_settings, settings, dd);
|
||
|
+ dd_close(dd);
|
||
|
+ /* WRONG! set_settings() does not copy the strings, it merely sets up pointers
|
||
|
+ * to settings[] dictionary:
|
||
|
+ */
|
||
|
+ /*free_map_string(settings);*/
|
||
|
+ }
|
||
|
+
|
||
|
+ /* No connection is opened between client and server. Users authentication
|
||
|
+ * is performed on every SOAP method call. In the first step we verify the
|
||
|
+ * credentials by calling 'mc_login' method. In the case the credentials are
|
||
|
+ * correctly applies the reporter uses them in the next requests. It is not
|
||
|
+ * necessary to call 'mc_login' method because the method provides only
|
||
|
+ * verification of credentials.
|
||
|
+ */
|
||
|
+ verify_credentials(&mbt_settings);
|
||
|
+
|
||
|
+ if (abrt_hash)
|
||
|
+ {
|
||
|
+ log(_("Looking for similar problems in CentOS Bug Tracker"));
|
||
|
+ GList *ids = mantisbt_search_by_abrt_hash(&mbt_settings, abrt_hash);
|
||
|
+ mantisbt_settings_free(&mbt_settings);
|
||
|
+
|
||
|
+ if (ids == NULL)
|
||
|
+ return EXIT_FAILURE;
|
||
|
+
|
||
|
+ puts(ids->data);
|
||
|
+ response_values_free(ids);
|
||
|
+ return EXIT_SUCCESS;
|
||
|
+ }
|
||
|
+
|
||
|
+ mantisbt_get_project_id_from_name(&mbt_settings);
|
||
|
+
|
||
|
+ if (opts & OPT_t)
|
||
|
+ {
|
||
|
+ if (!argv[0])
|
||
|
+ show_usage_and_die(program_usage_string, program_options);
|
||
|
+
|
||
|
+ if (!ticket_no)
|
||
|
+ {
|
||
|
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
|
||
|
+ if (!dd)
|
||
|
+ xfunc_die();
|
||
|
+ report_result_t *reported_to = find_in_reported_to(dd, "CentOS Bug Tracker");
|
||
|
+ dd_close(dd);
|
||
|
+
|
||
|
+ if (!reported_to || !reported_to->url)
|
||
|
+ error_msg_and_die(_("Can't get MantisBT ID because this problem has not yet been reported to MantisBT."));
|
||
|
+
|
||
|
+ char *url = reported_to->url;
|
||
|
+ reported_to->url = NULL;
|
||
|
+ free_report_result(reported_to);
|
||
|
+
|
||
|
+ if (prefixcmp(url, mbt_settings.m_mantisbt_url) != 0)
|
||
|
+ error_msg_and_die(_("This problem has been reported to MantisBT '%s' which differs from the configured MantisBT '%s'."), url, mbt_settings.m_mantisbt_url);
|
||
|
+
|
||
|
+ ticket_no = strrchr(url, '=');
|
||
|
+ if (!ticket_no)
|
||
|
+ error_msg_and_die(_("Malformed url to MantisBT '%s'."), url);
|
||
|
+
|
||
|
+ /* won't ever call free on it - it simplifies the code a lot */
|
||
|
+ ticket_no = xstrdup(ticket_no + 1);
|
||
|
+ log(_("Using CentOS Bug Tracker ID '%s'"), ticket_no);
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Attach files to existing MantisBT issues */
|
||
|
+ while (*argv)
|
||
|
+ {
|
||
|
+ const char *path = *argv++;
|
||
|
+ char *filename = basename(path);
|
||
|
+ log(_("Attaching file '%s' to issue %s"), filename, ticket_no);
|
||
|
+ mantisbt_attach_file(&mbt_settings, ticket_no, filename, path);
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Create new issue in MantisBT */
|
||
|
+
|
||
|
+ if (!(opts & OPT_f))
|
||
|
+ {
|
||
|
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
|
||
|
+ if (!dd)
|
||
|
+ xfunc_die();
|
||
|
+ report_result_t *reported_to = find_in_reported_to(dd, "CentOS Bug Tracker");
|
||
|
+ dd_close(dd);
|
||
|
+
|
||
|
+ if (reported_to && reported_to->url)
|
||
|
+ {
|
||
|
+ char *msg = xasprintf(_("This problem was already reported to CentOS Bug Tracker (see '%s')."
|
||
|
+ " Do you still want to create a new issue?"),
|
||
|
+ reported_to->url);
|
||
|
+ int yes = ask_yes_no(msg);
|
||
|
+ free(msg);
|
||
|
+ if (!yes)
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ free_report_result(reported_to);
|
||
|
+ }
|
||
|
+
|
||
|
+ problem_data_t *problem_data = create_problem_data_for_reporting(dump_dir_name);
|
||
|
+ if (!problem_data)
|
||
|
+ xfunc_die(); /* create_problem_data_for_reporting already emitted error msg */
|
||
|
+
|
||
|
+ const char *category = problem_data_get_content_or_die(problem_data, FILENAME_COMPONENT);
|
||
|
+ const char *duphash = problem_data_get_content_or_die(problem_data, FILENAME_DUPHASH);
|
||
|
+
|
||
|
+ if (opts & OPT_D)
|
||
|
+ {
|
||
|
+ problem_formatter_t *pf = problem_formatter_new();
|
||
|
+ problem_formatter_add_section(pf, PR_SEC_ADDITIONAL_INFO, /* optional section */ 0);
|
||
|
+
|
||
|
+ if (problem_formatter_load_file(pf, fmt_file))
|
||
|
+ error_msg_and_die("Invalid format file: %s", fmt_file);
|
||
|
+
|
||
|
+ problem_report_t *pr = NULL;
|
||
|
+ if (problem_formatter_generate_report(pf, problem_data, &pr))
|
||
|
+ error_msg_and_die("Failed to format issue report from problem data");
|
||
|
+
|
||
|
+ printf("summary: %s\n"
|
||
|
+ "\n"
|
||
|
+ "Description:\n%s\n"
|
||
|
+ "Additional info:\n%s\n"
|
||
|
+ , problem_report_get_summary(pr)
|
||
|
+ , problem_report_get_description(pr)
|
||
|
+ , problem_report_get_section(pr, PR_SEC_ADDITIONAL_INFO)
|
||
|
+ );
|
||
|
+
|
||
|
+ puts("attachments:");
|
||
|
+ for (GList *a = problem_report_get_attachments(pr); a != NULL; a = g_list_next(a))
|
||
|
+ printf(" %s\n", (const char *)a->data);
|
||
|
+
|
||
|
+ problem_report_free(pr);
|
||
|
+ problem_formatter_free(pf);
|
||
|
+ exit(0);
|
||
|
+ }
|
||
|
+
|
||
|
+ int bug_id = 0;
|
||
|
+
|
||
|
+ /* If REMOTE_RESULT contains "DUPLICATE 12345", we consider it a dup of 12345
|
||
|
+ * and won't search on MantisBT server.
|
||
|
+ */
|
||
|
+ char *remote_result;
|
||
|
+ remote_result = problem_data_get_content_or_NULL(problem_data, FILENAME_REMOTE_RESULT);
|
||
|
+ if (remote_result)
|
||
|
+ {
|
||
|
+ char *cmd = strtok(remote_result, " \n");
|
||
|
+ char *id = strtok(NULL, " \n");
|
||
|
+
|
||
|
+ if (!prefixcmp(cmd, "DUPLICATE"))
|
||
|
+ {
|
||
|
+ errno = 0;
|
||
|
+ char *e;
|
||
|
+ bug_id = strtoul(id, &e, 10);
|
||
|
+ if (errno || id == e || *e != '\0' || bug_id > INT_MAX)
|
||
|
+ {
|
||
|
+ /* error / no digits / illegal trailing chars / too big a number */
|
||
|
+ bug_id = 0;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ mantisbt_issue_info_t *ii;
|
||
|
+ if (!bug_id)
|
||
|
+ {
|
||
|
+ log(_("Checking for duplicates"));
|
||
|
+
|
||
|
+ int existing_id = -1;
|
||
|
+ int crossver_id = -1;
|
||
|
+ {
|
||
|
+ /* Figure out whether we want to match category
|
||
|
+ * when doing dup search.
|
||
|
+ */
|
||
|
+ const char *category_substitute = is_in_comma_separated_list(category, mbt_settings.m_DontMatchComponents) ? NULL : category;
|
||
|
+
|
||
|
+ /* We don't do dup detection across versions (see below why),
|
||
|
+ * but we do add a note if cross-version potential dup exists.
|
||
|
+ * For that, we search for cross version dups first:
|
||
|
+ */
|
||
|
+ // SOAP API searching method is not in the final version, it's possible the project will be string
|
||
|
+ GList *crossver_bugs_ids = mantisbt_search_duplicate_issues(&mbt_settings, category_substitute, /*version*/ NULL, duphash);
|
||
|
+
|
||
|
+ unsigned crossver_bugs_count = g_list_length(crossver_bugs_ids);
|
||
|
+ log_debug("CentOS Bug Tracker has %i reports with duphash '%s' including cross-version ones",
|
||
|
+ crossver_bugs_count, duphash);
|
||
|
+ if (crossver_bugs_count > 0)
|
||
|
+ crossver_id = atoi(g_list_first(crossver_bugs_ids)->data);
|
||
|
+
|
||
|
+ if (crossver_bugs_count > 0)
|
||
|
+ {
|
||
|
+ // SOAP API searching method is not in the final version, it's possible the project will be string
|
||
|
+ GList *dup_bugs_ids = mantisbt_search_duplicate_issues(&mbt_settings, category_substitute, mbt_settings.m_project_version, duphash);
|
||
|
+
|
||
|
+ unsigned dup_bugs_count = g_list_length(dup_bugs_ids);
|
||
|
+ log_debug("CentOS Bug Tracker has %i reports with duphash '%s'",
|
||
|
+ dup_bugs_count, duphash);
|
||
|
+ if (dup_bugs_count > 0)
|
||
|
+ existing_id = atoi(g_list_first(dup_bugs_ids)->data);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (existing_id < 0)
|
||
|
+ {
|
||
|
+ /* Create new issue */
|
||
|
+ log(_("Creating a new issue"));
|
||
|
+ problem_formatter_t *pf = problem_formatter_new();
|
||
|
+ problem_formatter_add_section(pf, PR_SEC_ADDITIONAL_INFO, 0);
|
||
|
+
|
||
|
+ if (problem_formatter_load_file(pf, fmt_file))
|
||
|
+ error_msg_and_die(_("Invalid format file: %s"), fmt_file);
|
||
|
+
|
||
|
+ problem_report_t *pr = NULL;
|
||
|
+ if (problem_formatter_generate_report(pf, problem_data, &pr))
|
||
|
+ error_msg_and_die(_("Failed to format problem data"));
|
||
|
+
|
||
|
+ if (crossver_id >= 0)
|
||
|
+ problem_report_buffer_printf(
|
||
|
+ problem_report_get_buffer(pr, PR_SEC_DESCRIPTION),
|
||
|
+ "\nPotential duplicate: issue %u\n", crossver_id);
|
||
|
+
|
||
|
+ problem_formatter_free(pf);
|
||
|
+
|
||
|
+ /* get tracker URL if exists */
|
||
|
+ struct dump_dir *dd = dd_opendir(dump_dir_name, 0);
|
||
|
+ char *tracker_url = NULL;
|
||
|
+ if (dd)
|
||
|
+ {
|
||
|
+ report_result_t *reported_to = find_in_reported_to(dd, tracker_str);
|
||
|
+ dd_close(dd);
|
||
|
+
|
||
|
+ if (reported_to && reported_to->url)
|
||
|
+ {
|
||
|
+ log(_("Adding External URL to issue"));
|
||
|
+ tracker_url = xstrdup(reported_to->url);
|
||
|
+ free_report_result(reported_to);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ int new_id = mantisbt_create_new_issue(&mbt_settings, problem_data, pr, tracker_url);
|
||
|
+
|
||
|
+ free(tracker_url);
|
||
|
+
|
||
|
+ if (new_id == -1)
|
||
|
+ return EXIT_FAILURE;
|
||
|
+
|
||
|
+ log(_("Adding attachments to issue %i"), new_id);
|
||
|
+ char *new_id_str = xasprintf("%u", new_id);
|
||
|
+
|
||
|
+ for (GList *a = problem_report_get_attachments(pr); a != NULL; a = g_list_next(a))
|
||
|
+ {
|
||
|
+ const char *item_name = (const char *)a->data;
|
||
|
+ struct problem_item *item = problem_data_get_item_or_NULL(problem_data, item_name);
|
||
|
+ if (!item)
|
||
|
+ continue;
|
||
|
+ else if (item->flags & CD_FLAG_TXT)
|
||
|
+ mantisbt_attach_data(&mbt_settings, new_id_str, item_name, item->content, strlen(item->content));
|
||
|
+ else if (item->flags & CD_FLAG_BIN)
|
||
|
+ mantisbt_attach_file(&mbt_settings, new_id_str, item_name, item->content);
|
||
|
+ }
|
||
|
+
|
||
|
+ free(new_id_str);
|
||
|
+ problem_report_free(pr);
|
||
|
+ ii = mantisbt_issue_info_new();
|
||
|
+ ii->mii_id = new_id;
|
||
|
+ ii->mii_status = xstrdup("new");
|
||
|
+
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ bug_id = existing_id;
|
||
|
+ }
|
||
|
+
|
||
|
+ ii = mantisbt_get_issue_info(&mbt_settings, bug_id);
|
||
|
+
|
||
|
+ log(_("Bug is already reported: %i"), ii->mii_id);
|
||
|
+
|
||
|
+ /* Follow duplicates */
|
||
|
+ if ((strcmp(ii->mii_status, "closed") == 0)
|
||
|
+ && (strcmp(ii->mii_resolution, "duplicate") == 0)
|
||
|
+ ) {
|
||
|
+ mantisbt_issue_info_t *origin = mantisbt_find_origin_bug_closed_duplicate(&mbt_settings, ii);
|
||
|
+ if (origin)
|
||
|
+ {
|
||
|
+ mantisbt_issue_info_free(ii);
|
||
|
+ ii = origin;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* TODO CC list
|
||
|
+ * Is no MantisBT SOAP API method which allows adding users to CC list
|
||
|
+ * without updating issue.
|
||
|
+ */
|
||
|
+
|
||
|
+ /* Add comment and bt */
|
||
|
+ const char *comment = problem_data_get_content_or_NULL(problem_data, FILENAME_COMMENT);
|
||
|
+ if (comment && comment[0])
|
||
|
+ {
|
||
|
+ problem_formatter_t *pf = problem_formatter_new();
|
||
|
+
|
||
|
+ if (problem_formatter_load_file(pf, fmt_file2))
|
||
|
+ error_msg_and_die(_("Invalid duplicate format file: '%s"), fmt_file2);
|
||
|
+
|
||
|
+ problem_report_t *pr;
|
||
|
+ if (problem_formatter_generate_report(pf, problem_data, &pr))
|
||
|
+ error_msg_and_die(_("Failed to format duplicate comment from problem data"));
|
||
|
+
|
||
|
+ const char *mbtcomment = problem_report_get_description(pr);
|
||
|
+
|
||
|
+ int dup_comment = is_comment_dup(ii->mii_notes, mbtcomment);
|
||
|
+ if (!dup_comment)
|
||
|
+ {
|
||
|
+ log(_("Adding new comment to issue %d"), ii->mii_id);
|
||
|
+ mantisbt_add_issue_note(&mbt_settings, ii->mii_id, mbtcomment);
|
||
|
+
|
||
|
+ const char *bt = problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE);
|
||
|
+ unsigned rating = 0;
|
||
|
+ const char *rating_str = problem_data_get_content_or_NULL(problem_data, FILENAME_RATING);
|
||
|
+ /* python doesn't have rating file */
|
||
|
+ if (rating_str)
|
||
|
+ rating = xatou(rating_str);
|
||
|
+ if (bt && rating > ii->mii_best_bt_rating)
|
||
|
+ {
|
||
|
+ char *bug_id_str = xasprintf("%i", ii->mii_id);
|
||
|
+
|
||
|
+ log(_("Attaching better backtrace"));
|
||
|
+
|
||
|
+ // find unique filename of attachment
|
||
|
+ char *name = NULL;
|
||
|
+ for (int i = 0;; ++i)
|
||
|
+ {
|
||
|
+ if (i == 0)
|
||
|
+ name = xasprintf("%s", FILENAME_BACKTRACE);
|
||
|
+ else
|
||
|
+ name = xasprintf("%s%d", FILENAME_BACKTRACE, i);
|
||
|
+
|
||
|
+ if (g_list_find_custom(ii->mii_attachments, name, (GCompareFunc) strcmp) == NULL)
|
||
|
+ break;
|
||
|
+
|
||
|
+ free(name);
|
||
|
+ }
|
||
|
+ mantisbt_attach_data(&mbt_settings, bug_id_str, name, bt, strlen(bt));
|
||
|
+
|
||
|
+ free(name);
|
||
|
+ free(bug_id_str);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else
|
||
|
+ log(_("Found the same comment in the issue history, not adding a new one"));
|
||
|
+
|
||
|
+ problem_report_free(pr);
|
||
|
+ problem_formatter_free(pf);
|
||
|
+ }
|
||
|
+
|
||
|
+finish:
|
||
|
+ log(_("Status: %s%s%s %s/view.php?id=%u"),
|
||
|
+ ii->mii_status,
|
||
|
+ ii->mii_resolution ? " " : "",
|
||
|
+ ii->mii_resolution ? ii->mii_resolution : "",
|
||
|
+ mbt_settings.m_mantisbt_url,
|
||
|
+ ii->mii_id);
|
||
|
+
|
||
|
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
|
||
|
+ if (dd)
|
||
|
+ {
|
||
|
+ char *msg = xasprintf("CentOS Bug Tracker: URL=%s/view.php?id=%u", mbt_settings.m_mantisbt_url, ii->mii_id);
|
||
|
+ add_reported_to(dd, msg);
|
||
|
+ free(msg);
|
||
|
+ dd_close(dd);
|
||
|
+ }
|
||
|
+
|
||
|
+ mantisbt_settings_free(&mbt_settings);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
diff --git a/src/workflows/Makefile.am b/src/workflows/Makefile.am
|
||
|
index 0fc1019..5b8376a 100644
|
||
|
--- a/src/workflows/Makefile.am
|
||
|
+++ b/src/workflows/Makefile.am
|
||
|
@@ -22,6 +22,18 @@ dist_workflows_DATA = \
|
||
|
workflow_Logger.xml \
|
||
|
workflow_LoggerCCpp.xml
|
||
|
|
||
|
+if BUILD_MANTISBT
|
||
|
+dist_workflows_DATA += \
|
||
|
+ workflow_CentOSCCpp.xml \
|
||
|
+ workflow_CentOSKerneloops.xml \
|
||
|
+ workflow_CentOSPython.xml \
|
||
|
+ workflow_CentOSPython3.xml \
|
||
|
+ workflow_CentOSVmcore.xml \
|
||
|
+ workflow_CentOSXorg.xml \
|
||
|
+ workflow_CentOSLibreport.xml \
|
||
|
+ workflow_CentOSJava.xml
|
||
|
+endif
|
||
|
+
|
||
|
if BUILD_BUGZILLA
|
||
|
dist_workflows_DATA += \
|
||
|
workflow_AnacondaFedora.xml \
|
||
|
@@ -44,7 +56,8 @@ dist_workflowsdef_DATA =\
|
||
|
report_rhel.conf \
|
||
|
report_mailx.conf \
|
||
|
report_logger.conf \
|
||
|
- report_uploader.conf
|
||
|
+ report_uploader.conf \
|
||
|
+ report_centos.conf
|
||
|
|
||
|
if BUILD_BUGZILLA
|
||
|
dist_workflowsdef_DATA += \
|
||
|
diff --git a/src/workflows/report_centos.conf b/src/workflows/report_centos.conf
|
||
|
new file mode 100644
|
||
|
index 0000000..07b0d40
|
||
|
--- /dev/null
|
||
|
+++ b/src/workflows/report_centos.conf
|
||
|
@@ -0,0 +1,31 @@
|
||
|
+EVENT=workflow_CentOSLibreport analyzer=libreport
|
||
|
+# this is just a meta event which consists of other events
|
||
|
+# the list is defined in the xml file
|
||
|
+
|
||
|
+EVENT=workflow_CentOSCCpp analyzer=CCpp
|
||
|
+# this is just a meta event which consists of other events
|
||
|
+# the list is defined in the xml file
|
||
|
+
|
||
|
+EVENT=workflow_CentOSPython analyzer=Python component!=anaconda
|
||
|
+# this is just a meta event which consists of other events
|
||
|
+# the list is defined in the xml file
|
||
|
+
|
||
|
+EVENT=workflow_CentOSPython3 analyzer=Python3 component!=anaconda
|
||
|
+# this is just a meta event which consists of other events
|
||
|
+# the list is defined in the xml file
|
||
|
+
|
||
|
+EVENT=workflow_CentOSKerneloops analyzer=Kerneloops
|
||
|
+# this is just a meta event which consists of other events
|
||
|
+# the list is defined in the xml file
|
||
|
+
|
||
|
+EVENT=workflow_CentOSVmcore analyzer=vmcore
|
||
|
+# this is just a meta event which consists of other events
|
||
|
+# the list is defined in the xml file
|
||
|
+
|
||
|
+EVENT=workflow_CentOSXorg analyzer=xorg
|
||
|
+# this is just a meta event which consists of other events
|
||
|
+# the list is defined in the xml file
|
||
|
+
|
||
|
+EVENT=workflow_CentOSJava analyzer=Java
|
||
|
+# this is just a meta event which consists of other events
|
||
|
+# the list is defined in the xml file
|
||
|
diff --git a/src/workflows/workflow_CentOSCCpp.xml.in b/src/workflows/workflow_CentOSCCpp.xml.in
|
||
|
new file mode 100644
|
||
|
index 0000000..ea94d56
|
||
|
--- /dev/null
|
||
|
+++ b/src/workflows/workflow_CentOSCCpp.xml.in
|
||
|
@@ -0,0 +1,12 @@
|
||
|
+<?xml version="1.0" encoding="UTF-8" ?>
|
||
|
+<workflow>
|
||
|
+ <_name>Report to CentOS Bug Tracker</_name>
|
||
|
+ <_description>Process the C/C++ crash using the CentOS infrastructure</_description>
|
||
|
+
|
||
|
+ <events>
|
||
|
+ <event>report_uReport</event>
|
||
|
+ <event>collect_*</event>
|
||
|
+ <event>analyze_CCpp</event>
|
||
|
+ <event>report_CentOSBugTracker</event>
|
||
|
+ </events>
|
||
|
+</workflow>
|
||
|
diff --git a/src/workflows/workflow_CentOSJava.xml.in b/src/workflows/workflow_CentOSJava.xml.in
|
||
|
new file mode 100644
|
||
|
index 0000000..89f9295
|
||
|
--- /dev/null
|
||
|
+++ b/src/workflows/workflow_CentOSJava.xml.in
|
||
|
@@ -0,0 +1,11 @@
|
||
|
+<?xml version="1.0" encoding="UTF-8" ?>
|
||
|
+<workflow>
|
||
|
+ <_name>Report to CentOS Bug Tracker</_name>
|
||
|
+ <_description>Process the Java exception using the CentOS infrastructure</_description>
|
||
|
+
|
||
|
+ <events>
|
||
|
+ <event>report_uReport</event>
|
||
|
+ <event>collect_*</event>
|
||
|
+ <event>report_CentOSBugTracker</event>
|
||
|
+ </events>
|
||
|
+</workflow>
|
||
|
diff --git a/src/workflows/workflow_CentOSKerneloops.xml.in b/src/workflows/workflow_CentOSKerneloops.xml.in
|
||
|
new file mode 100644
|
||
|
index 0000000..c43c681
|
||
|
--- /dev/null
|
||
|
+++ b/src/workflows/workflow_CentOSKerneloops.xml.in
|
||
|
@@ -0,0 +1,11 @@
|
||
|
+<?xml version="1.0" encoding="UTF-8" ?>
|
||
|
+<workflow>
|
||
|
+ <_name>Report to CentOS Bug Tracker</_name>
|
||
|
+ <_description>Process the kerneloops using the CentOS infrastructure</_description>
|
||
|
+
|
||
|
+ <events>
|
||
|
+ <event>report_uReport</event>
|
||
|
+ <event>collect_*</event>
|
||
|
+ <event>report_CentOSBugTracker</event>
|
||
|
+ </events>
|
||
|
+</workflow>
|
||
|
diff --git a/src/workflows/workflow_CentOSLibreport.xml.in b/src/workflows/workflow_CentOSLibreport.xml.in
|
||
|
new file mode 100644
|
||
|
index 0000000..2f6ed82
|
||
|
--- /dev/null
|
||
|
+++ b/src/workflows/workflow_CentOSLibreport.xml.in
|
||
|
@@ -0,0 +1,9 @@
|
||
|
+<?xml version="1.0" encoding="UTF-8" ?>
|
||
|
+<workflow>
|
||
|
+ <_name>Report to CentOS Bug Tracker</_name>
|
||
|
+ <_description>Process the problem using the CentOS infrastructure</_description>
|
||
|
+
|
||
|
+ <events>
|
||
|
+ <event>report_CentOSBugTracker</event>
|
||
|
+ </events>
|
||
|
+</workflow>
|
||
|
diff --git a/src/workflows/workflow_CentOSPython.xml.in b/src/workflows/workflow_CentOSPython.xml.in
|
||
|
new file mode 100644
|
||
|
index 0000000..7e26c6c
|
||
|
--- /dev/null
|
||
|
+++ b/src/workflows/workflow_CentOSPython.xml.in
|
||
|
@@ -0,0 +1,11 @@
|
||
|
+<?xml version="1.0" encoding="UTF-8" ?>
|
||
|
+<workflow>
|
||
|
+ <_name>Report to CentOS Bug Tracker</_name>
|
||
|
+ <_description>Process the python exception using the CentOS infrastructure</_description>
|
||
|
+
|
||
|
+ <events>
|
||
|
+ <event>report_uReport</event>
|
||
|
+ <event>collect_*</event>
|
||
|
+ <event>report_CentOSBugTracker</event>
|
||
|
+ </events>
|
||
|
+</workflow>
|
||
|
diff --git a/src/workflows/workflow_CentOSPython3.xml.in b/src/workflows/workflow_CentOSPython3.xml.in
|
||
|
new file mode 100644
|
||
|
index 0000000..f1dd8a9
|
||
|
--- /dev/null
|
||
|
+++ b/src/workflows/workflow_CentOSPython3.xml.in
|
||
|
@@ -0,0 +1,11 @@
|
||
|
+<?xml version="1.0" encoding="UTF-8" ?>
|
||
|
+<workflow>
|
||
|
+ <_name>Report to CentOS Bug Tracker</_name>
|
||
|
+ <_description>Process the python 3 exception using the CentOS infrastructure</_description>
|
||
|
+
|
||
|
+ <events>
|
||
|
+ <event>report_uReport</event>
|
||
|
+ <event>collect_*</event>
|
||
|
+ <event>report_CentOSBugTracker</event>
|
||
|
+ </events>
|
||
|
+</workflow>
|
||
|
diff --git a/src/workflows/workflow_CentOSVmcore.xml.in b/src/workflows/workflow_CentOSVmcore.xml.in
|
||
|
new file mode 100644
|
||
|
index 0000000..c876594
|
||
|
--- /dev/null
|
||
|
+++ b/src/workflows/workflow_CentOSVmcore.xml.in
|
||
|
@@ -0,0 +1,12 @@
|
||
|
+<?xml version="1.0" encoding="UTF-8" ?>
|
||
|
+<workflow>
|
||
|
+ <_name>Report to CentOS Bug Tracker</_name>
|
||
|
+ <_description>Process the kernel crash using the CentOS infrastructure</_description>
|
||
|
+
|
||
|
+ <events>
|
||
|
+ <event>analyze_VMcore</event>
|
||
|
+ <event>report_uReport</event>
|
||
|
+ <event>collect_*</event>
|
||
|
+ <event>report_CentOSBugTracker</event>
|
||
|
+ </events>
|
||
|
+</workflow>
|
||
|
diff --git a/src/workflows/workflow_CentOSXorg.xml.in b/src/workflows/workflow_CentOSXorg.xml.in
|
||
|
new file mode 100644
|
||
|
index 0000000..bf52221
|
||
|
--- /dev/null
|
||
|
+++ b/src/workflows/workflow_CentOSXorg.xml.in
|
||
|
@@ -0,0 +1,9 @@
|
||
|
+<?xml version="1.0" encoding="UTF-8" ?>
|
||
|
+<workflow>
|
||
|
+ <_name>Report to CentOS Bug Tracker</_name>
|
||
|
+ <_description>Process the X Server problem using the CentOS infrastructure</_description>
|
||
|
+
|
||
|
+ <events>
|
||
|
+ <event>report_CentOSBugTracker</event>
|
||
|
+ </events>
|
||
|
+</workflow>
|
||
|
--
|
||
|
1.8.3.1
|
||
|
|