Jira 用于错误跟踪和客户支持?

2023-12-22

我们正在考虑使用 Jira 进行错误跟踪,并将其与 Git 集成,以将错误修复与版本处理联系起来。

您是否也推荐 Jira 来提供客户支持,还是我们应该寻找其他系统(例如 Zendesk)来实现此目的?我知道可以通过某种方式将 Hipchat 与 Jira 集成,以启用与客户的聊天功能,但 Jira 是否太复杂,客户服务无法处理?你的经验是什么?


我们使用 Jira 进行客户支持,但我们发现 Jira 缺少许多为此所需的必备功能。这就是我们做出许多改变的原因。

总而言之,我们对自己的选择非常满意,并且通过使用 Jira 而不是其他解决方案,我们节省了大量资金。

以下是我们所做的主要更改,这将向您展示缺少的内容,而另一方面向您展示,只需一点点编程,Jira 就可以做任何事情:)

注意:下面编写的脚本应附加到工作流程转换。脚本是使用编写的Jython http://www.jython.org/,所以需要安装才能使用。

通过电子邮件创建问题

Jira 仅向 Jira 用户发送电子邮件。由于我们不想为每个提供支持的人创建一个用户,因此我们使用匿名用户,并使用脚本向他们发送电子邮件。

首先,将 Jira 设置为从电子邮件创建问题 https://confluence.atlassian.com/display/JIRA/Creating+Issues+and+Comments+from+Email。比,使用脚本运行器插件 https://marketplace.atlassian.com/plugins/com.onresolve.jira.groovy.groovyrunner将客户的电子邮件和姓名保存到自定义字段。 。代码:

from com.atlassian.jira import ComponentManager
import re
cfm = ComponentManager.getInstance().getCustomFieldManager()

# read issue description
description = issue.getDescription()
if (description is not None) and ('Created via e-mail received from' in description):
    # extract email and name:
    if ('<' in description) and ('>' in description):
        # pattern [Created via e-mail received from: name <[email protected] /cdn-cgi/l/email-protection>]
        # split it to a list
        description_list = re.split('<|>|:',description)
        list_length = len(description_list)
        for index in range(list_length-1, -1, -1):
            if '@' in description_list[index]:
                customer_email = description_list[index]
                customer_name = description_list[index - 1]
                break
    else:
        # pattern [Created via e-mail received from: [email protected] /cdn-cgi/l/email-protection]
        customer_name = "Sir or Madam"
        # split it to a list  
        description_list = re.split(': |]',description)
        list_length = len(description_list)
        for index in range(list_length-1, -1, -1):
            if '@' in description_list[index]:
                customer_email = description_list[index]
                break

    # if the name isn't in the right form, switch it's places:
    if (customer_name[0] == '"') and (customer_name[-1] == '"') and (',' in customer_name):
        customer_name = customer_name[1:-1]
        i =  customer_name.index(',')
        customer_name = customer_name[i+2:]+" "+customer_name[:i]

    # insert data to issue fields
    issue.setCustomFieldValue(cfm.getCustomFieldObject("customfield_10401"),customer_email)
    issue.setCustomFieldValue(cfm.getCustomFieldObject("customfield_10108"),customer_name)

送客户issue created通知

使用以下脚本发送邮件:

import smtplib,email
from smtplib import SMTP 
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
import os
import re
from com.atlassian.jira import ComponentManager

customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
cfm = ComponentManager.getInstance().getCustomFieldManager()

# read needed fields from the issue
key = issue.getKey()
#status = issue.getStatusObject().name
summary = issue.getSummary()
project = issue.getProjectObject().name

# read customer email address
toAddr = issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10401"))
# send mail only if a valid email was entered
if (toAddr is not None) and (re.match('[A-Za-z0-9._%+-]+@(?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,4}',toAddr)):
    # read customer name
    customerName = issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10108"))
    # read template from the disk
    template_file = 'new_case.template'
    f = open(template_file, 'r')
    htmlBody = ""
    for line in f:
        line = line.replace('$$CUSTOMER_NAME',customerName)
        line = line.replace('$$KEY',key)
        line = line.replace('$$PROJECT',project)
        line = line.replace('$$SUMMARY',summary)
        htmlBody += line + '<BR>'


    smtpserver = 'smtpserver.com'
    to = [toAddr]
    fromAddr = '[email protected] /cdn-cgi/l/email-protection'
    subject = "["+key+"] Thank You for Contacting Support team"
    mail_user = '[email protected] /cdn-cgi/l/email-protection'
    mail_password = 'password'

    # create html email
    html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" '
    html +='"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">'
    html +='<body style="font-size:12px;font-family:Verdana">'
    html +='<p align="center"><img src="http://path/to/company_logo.jpg" alt="logo"></p> '
    html +='<p>'+htmlBody+'</p>'
    html +='</body></html>'

    emailMsg = email.MIMEMultipart.MIMEMultipart('alternative')
    emailMsg['Subject'] = subject
    emailMsg['From'] = fromAddr
    emailMsg['To'] = ', '.join(to)
    emailMsg.attach(email.mime.text.MIMEText(html,'html'))

    # Send the email
    s = SMTP(smtpserver) # ip or domain name of smtp server
    s.login(mail_user, mail_password)   
    s.sendmail(fromAddr, [to], emailMsg.as_string())
    s.quit()

    # add sent mail to comments
    cm = ComponentManager.getInstance().getCommentManager()
    email_body = htmlBody.replace('<BR>','\n')
    cm.create(issue,'anonymous','Email was sent to the customer ; Subject: '+subject+'\n'+email_body,False)

内容new_case.template:

Dear $$CUSTOMER_NAME,

Thank you for contacting support team.

We will address your case as soon as possible and respond with a solution very quickly.

Issue key $$KEY has been created as a reference for future correspondence.

If you need urgent support please refer to our Frequently Asked Questions page at http://www.example.com/faq.

Thank you,

Support Team


Issue key: $$KEY
Issue subject: $$PROJECT
Issue summary: $$SUMMARY

问题提醒-开放24/36/48小时通知

  • 创建了一个名为“打开时间”的自定义字段 - 一个“日期时间”字段,用于保存问题打开的时间。
  • 创建了一个名为“通知”的自定义字段 - 一个只读文本字段。
  • 使用脚本运行器插件 https://marketplace.atlassian.com/plugins/com.onresolve.jira.groovy.groovyrunner,我创建了一个后置函数并将其放置在每次进入“打开”状态的转换上。这是为了保持问题开放时间。

代码:

from com.atlassian.jira import ComponentManager
from datetime import datetime

opend_since_field = "customfield_10001"

# get opened since custom field:
cfm = ComponentManager.getInstance().getCustomFieldManager()
# get current time
currentTime = datetime.today()
# save current time
issue.setCustomFieldValue(cfm.getCustomFieldObject(opend_since_field),currentTime)
  • 我创建了一个新的过滤器来获取开放时间超过 24 小时的问题列表:

JQL:

project = XXX AND status= Open ORDER BY updated ASC, key DESC
  • 最后 - 我用过Jira远程API https://developer.atlassian.com/display/JIRADEV/JIRA+Remote+API+Reference - the XML-RPC https://developer.atlassian.com/display/JIRADEV/JIRA+XML-RPC+Overview方法编写一个Python脚本,计划每5分钟运行一次。剧本 读取过滤器中发出的所有邮件,提取所有超过 24 小时/36 小时/48 小时处于“打开”状态的邮件,发送提醒电子邮件,并将其标记为已通知,因此每种类型只会发送一个提醒。

蟒蛇代码:

#!/usr/bin/python

# Refer to the XML-RPC Javadoc to see what calls are available:
# http://docs.atlassian.com/software/jira/docs/api/rpc-jira-plugin/latest/com/atlassian/jira/rpc/xmlrpc/XmlRpcService.html
# /home/issues_reminder.py

import xmlrpclib
import time
from time import mktime
from datetime import datetime
from datetime import timedelta
import smtplib,email
from smtplib import SMTP 
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders

# Jira connction info
server = 'https://your.jira.com/rpc/xmlrpc'
user = 'user'
password = 'password'
filter = '10302' # Filter ID
# Email definitions 
smtpserver = 'mail.server.com'
fromAddr = '[email protected] /cdn-cgi/l/email-protection'
mail_user = '[email protected] /cdn-cgi/l/email-protection'
mail_password = 'password'
toAddr = '[email protected] /cdn-cgi/l/email-protection'
mysubject = "hrs Issue notification!!!"
opend_since_field = "customfield_10101"


COMMASPACE = ', '
def email_issue(issue,esc_time):
    # create html email
    subject = '['+issue+'] '+esc_time+mysubject
    html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" '
    html +='"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">'
    html +='<body style="font-size:12px;font-family:Verdana">'
    html +='<p align="center"><img src="your_logo.jpg" alt="logo" height="43" width="198"></p> '
    html +='<p> The issue ['+issue+'] is open for over '+esc_time+' hours.</p>'
    html +='<p> A link to view the issue: https://your.jira.com/browse/'+issue+'.</p>'
    html +='<BR><p> This is an automated email sent from Jira.</p>'
    html +='</body></html>'
    emailMsg = email.MIMEMultipart.MIMEMultipart('alternative')
    emailMsg['Subject'] = subject
    emailMsg['From'] = fromAddr
    emailMsg['To'] = toAddr
    emailMsg.attach(MIMEText(html, 'html'))
    # Send the email
    emailserver = SMTP(smtpserver) # ip or domain name of smtp server
    emailserver.login(mail_user, mail_password)
    emailserver.sendmail(fromAddr, [toAddr], emailMsg.as_string())
    emailserver.quit()
    return


s = xmlrpclib.ServerProxy(server)
auth = s.jira1.login(user, password)

esc12List = []
esc24List = []
esc48List = []


issues = s.jira1.getIssuesFromFilter(auth, filter)
print "Modifying issue..."
for issue in issues:
        creation = 0;
        # get open since time
        for customFields in issue['customFieldValues']:
                if customFields['customfieldId'] == opend_since_field :
                        print "found field!"+  customFields['values']
                        creation = customFields['values']
        if (creation == 0):
                creation = issue['created']
                print "field not found"
    creationTime = datetime.fromtimestamp(mktime(time.strptime(creation, '%d/%b/%y %I:%M %p')))
    currentTime = datetime.fromtimestamp(mktime(time.gmtime()))
    delta = currentTime - creationTime
    esc12 = timedelta(hours=12)
    esc24 = timedelta(hours=24)
    esc48 = timedelta(hours=48)
    print "\nchecking issue "+issue['key']
    if (delta < esc12):
        print "less than 12 hours"
        print "not updating"
        continue
    if (delta < esc24):
        print "less than 24 hours"
        for customFields in issue['customFieldValues']:
            if customFields['customfieldId'] == 'customfield_10412':
                if customFields['values'] == '12h':
                    print "not updating"
                    break
                else:
                    print "updating !!!"
                    s.jira1.updateIssue(auth, issue['key'], {"customfield_10412": ["12h"]})
                    esc12List.append(issue['key'])
                    break
        continue
    if (delta < esc48):
        print "less than 48 hours"
        for customFields in issue['customFieldValues']:
            if customFields['customfieldId'] == 'customfield_10412':
                if customFields['values'] == '24h':
                    print "not updating"
                    break
                else:
                    print "updating !!!"
                    s.jira1.updateIssue(auth, issue['key'], {"customfield_10412": ["24h"]})
                    esc24List.append(issue['key'])
                    break
        continue
    print "more than 48 hours"
    for customFields in issue['customFieldValues']:
        if customFields['customfieldId'] == 'customfield_10412':
            if customFields['values'] == '48h':
                print "not updating"
                break
            else:
                print "updating !!!"
                s.jira1.updateIssue(auth, issue['key'], {"customfield_10412": ["48h"]})
                esc48List.append(issue['key'])
                break

for key in esc12List:
    email_issue(key,'12')
for key in esc24List:
    email_issue(key,'24')
for key in esc48List:
    email_issue(key,'48')

此方法的主要优点是它具有高度可定制性,并且通过将数据保存到自定义字段,可以轻松创建过滤器和报告以显示长期存在的问题。

升级至开发团队

创建一个新的过渡 -Escalate。这将为开发团队创建一个问题,并将新问题链接到支持问题。添加以下post函数:

from com.atlassian.jira.util import ImportUtils
from com.atlassian.jira import ManagerFactory
from com.atlassian.jira.issue import MutableIssue
from com.atlassian.jira import ComponentManager
from com.atlassian.jira.issue.link import DefaultIssueLinkManager
from org.ofbiz.core.entity import GenericValue;

# get issue objects
issueManager = ComponentManager.getInstance().getIssueManager()
issueFactory = ComponentManager.getInstance().getIssueFactory()
authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
issueLinkManager = ComponentManager.getInstance().getIssueLinkManager()
customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
userUtil = ComponentManager.getInstance().getUserUtil()
projectMgr = ComponentManager.getInstance().getProjectManager()
customer_name = customFieldManager.getCustomFieldObjectByName("Customer Name")
customer_email = customFieldManager.getCustomFieldObjectByName("Customer Email")
escalate = customFieldManager.getCustomFieldObjectByName("Escalate to Development")

if issue.getCustomFieldValue(escalate) is not None:
    # define issue
    issueObject = issueFactory.getIssue()
    issueObject.setProject(projectMgr.getProject(10000))
    issueObject.setIssueTypeId("1") # bug
    # set subtask attributes
    issueObject.setSummary("[Escalated from support] "+issue.getSummary())
    issueObject.setAssignee(userUtil.getUserObject("nadav"))
    issueObject.setReporter(issue.getAssignee())
    issueObject.setDescription(issue.getDescription())
    issueObject.setCustomFieldValue(customer_name, issue.getCustomFieldValue(customer_name)+" "+issue.getCustomFieldValue(customer_email))
    issueObject.setComponents(issue.getComponents())
    # Create subtask 
    subTask = issueManager.createIssue(authenticationContext.getUser(), issueObject)
    # Link parent issue to subtask
    issueLinkManager.createIssueLink(issueObject.getId(),issue.getId(),10003,1,authenticationContext.getUser())
    # Update search indexes
    ImportUtils.setIndexIssues(True);
    ComponentManager.getInstance().getIndexManager().reIndex(subTask)
    ImportUtils.setIndexIssues(False)

转向销售

创建一个新的过渡 -Move to sales。许多支持电话最终都会变成销售电话,这会将问题转移给销售团队。添加以下post函数:

from com.atlassian.jira.util import ImportUtils
from com.atlassian.jira.issue import MutableIssue
from com.atlassian.jira import ComponentManager

customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
userUtil = ComponentManager.getInstance().getUserUtil()

issue.setStatusId("1");
issue.setAssignee(userUtil.getUserObject("John"))
issue.setSummary("[Moved from support] "+issue.getSummary())
issue.setProjectId(10201);
issue.setIssueTypeId("35");
ImportUtils.setIndexIssues(True);
ComponentManager.getInstance().getIndexManager().reIndex(issue)
ImportUtils.setIndexIssues(False)


# add to comments
from time import gmtime, strftime
time = strftime("%d-%m-%Y %H:%M:%S", gmtime())
cm = ComponentManager.getInstance().getCommentManager()
currentUser = ComponentManager.getInstance().getJiraAuthenticationContext().getUser().toString()
cm.create(issue,currentUser,'Email was moved to Sales at '+time,False)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Jira 用于错误跟踪和客户支持? 的相关文章

  • Jira、Redmine横向对比:哪个更适合做研发项目管理

    如果你是一个软件开发团队的成员或者负责人 你可能会遇到这样的问题 该选择哪种项目管理和协作工具来提高工作效率和质量 市面上有很多这样的工具 比如 Redmine 和 Jira 它们都有各自的优缺点 适合不同的场景和需求 本文将从以下几个方面
  • 登录 jirasoapapi

    我尝试在 C 上使用 jirasoap api 在VS2010中创建新项目 添加Web服务参考 JiraTest http jira atlassian com rpc soap jirasoapservice v2 wsdl 编写下一个代
  • 如何使用 REST API 在 Jira 中创建问题?

    如何使用 REST API 在 Jira 中创建问题 我已经尝试过使用curl 的示例 但我需要使用 Java 和 REST API 在 Eclipse 中创建缺陷 您想将 JIRA 集成到 Eclipse 中吗 See https con
  • 在 PHP 中使用soap 添加 Jira 注释 [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 如何在 PHP 中使用 SOAP 在 Jira 中添加注释 soapClient
  • 通过Python suds在JIRA中创建问题时设置受让人字段

    使用 JIRA 版本 4 2 使用 Python 2 7 和 suds 0 4 如何创建受让人字段集的问题 下面的代码中将忽略受让人字段 new issue client service createIssue auth project N
  • 使用 JQL 过滤特定用户在一段时间内更新的问题

    有没有办法使用 JQL 查找特定用户在每天特定时间段更新的所有问题 或者是否有任何插件可以解决这个问题 如果更新意味着状态改变 你可以检查如下内容 status changed by user name and updated gt sta
  • 从字符串加载.Net中的Jira公共证书(如何将ASN.1编码的SubjectPublicKeyInfo转换为.Net中的X509证书)

    我正在构建一个 oauth 1 0a 服务 该服务将由 Jira 中的小工具使用 它是一个用 C 编写的 Net 3 5 应用程序 Jira 使用 RSA SHA1 签名方法向此服务发出请求 这意味着要验证请求的签名 我需要从其公共证书创建
  • JIRA:查找与用户相关的所有问题

    在 JIRA 中 如何查找所有项目中与用户相关的所有问题 简单的查询搜索仅产生全文结果 即 仅涉及名称被提及的问题 而不是名称已被分配 已报告 已抄送等的问题 我在这里的目的是寻找与我相关的股票会计票据 我使用的是 JIRA 3 13 as
  • JIRA JQL:按阻止状态对卡片进行着色

    我正在尝试使用 JIRA Agile 的 卡片颜色 功能以及 ScriptRunner 插件 为 JIRA Agile 板上的阻塞卡片着色 我对 被阻止 的定义是 票证具有 被阻止 字段的值 或者以 被阻止 关系链接到未解决的票证 我能做的
  • 在 R 中将 cURL 转换为 httr

    与 Zendesk API 通信时 我在将 cURL 请求转换为 httr post 请求时遇到问题 我已成功从 API 中提取数据 但到目前为止发布数据存在问题 我已经与 Zendesk 的 API 支持人员交谈过 但不幸的是 他们没有任
  • Jira:从没有主题的电子邮件创建问题和评论

    我正在寻找一种方法来控制 从电子邮件创建问题和评论 的工作方式 目前 由于我们使用内置系统 任何收到的没有主题的电子邮件都会导致服务失败 并显示消息 问题必须有摘要 邮件消息的主题为空或没有主题 每次发生这种情况时 我们都必须手动处理电子邮
  • 预接收挂钩被拒绝:提交消息中未发现 JIRA 问题?

    我已经提交并尝试将更改推送到存储库 但它给了我这个错误 remote refs heads feature OMT 1270 Missing French Translations cd54ab15bc8d5764ab12cf6fc202f
  • keytool 错误:java.lang.Exception:输入不是 X.509 证书

    我正在尝试导入 Gmails smtp 证书以与 Jira 一起使用 但在使用 Javas keytool 导入时出现此错误 我使用 openssl 来获取证书 包括 Begin Certificate 和 End Certificate
  • 通过 JIRA REST API 从自定义字段获取值

    我想获取自定义字段的所有下拉选项 对于系统字段 我使用以下 URI http localhost 8080 rest api 2 project XXXX components http localhost 8080 rest api 2
  • 如何使用 JQL 检索特定状态的问题

    输入 url 或使用curl 运行 例如 https
  • 向 Jira 的 api 添加附件

    我正在尝试使用他们的 API 将文件附加到 Jira 案例 我在 Drupal 6 PHP v 5 0 中执行此操作 这是我的代码 ch curl init header array Content Type multipart form
  • 如何将 Jira 问题收集器与 Angular 应用程序集成?

    我正在创建一个 Angular 7 应用程序 它利用 Jira 问题收集器将问题直接提交到各自的项目 当我按照现在的方式构建应用程序时 什么也没有发生 当我直接将代码从方法 submitIssue 移动到 ngOnInIt 下时 会出现问题
  • 如何使用 JIRA REST API 获取项目中的所有冲刺

    是否有类似 https www example com jira rest agile 1 0 sprint project XYZ 之类的内容来检索 JIRA Software 项目中的所有冲刺 JIRA 平台 API 可以检索项目信息
  • JIRA JQL 按日期搜索 - 有没有办法获取 Today()(日期)而不是 Now()(日期时间)

    我正在尝试在 JIRA 中基于以下内容创建一些问题过滤器CreateDate 我能找到的唯一日期 时间函数是Now 以及与之相关的搜索 即 1d 4d 等 唯一的问题是 Now 是特定于时间的 因此无法获取特定日期创建的问题 i e Cre
  • Jira问题提醒

    当问题开放 24 36 48 小时时 如何通过电子邮件向预定义的邮件组创建通知 对于这些类型中的任何一种 24 36 48 都应该有一个提醒 如果重新打开问题 则应重新开始计数 我总体上同意库夫的方法 但是最近的 JIRA 插件版本自动化插

随机推荐