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支持reopen率的统计

    jira本身并不能统计bug的reopen率 虽然bug工作流程中有reopen节点 只能借助第三方插件来处理 插件名称 Enhancer Plugin for JIRA 此插件支持自定义字段 自定义计数器等等高级操作 在插件管理中搜索插件
  • Jira 史诗指南 (2022)

    Jira 就是为了完成工作 而 Epics 是实现该目标的一种有价值的方式 一般来说 Epics 适用于顾名思义 不会在一天内完成但会 的工作 史诗 在本指南中 我们将分解什么是 Epics 它们的用途 以及它们的用途 以及如何创建和使用它
  • 进度管理计划7个过程及相关重点

    概述 1 规划进度管理 规划 编制 管理 执行和控制项目进度而制定政策 程序和文档过程 2 定义活动 识别和记录为完成项目可交付成果而采取的具体行动的过程 3 排列活动顺序 识别和记录项目活动之间的关系的过程 4 估算活动资源 估算执行各项
  • 运维知识各种链接

    转自 https www cnblogs com uglyliu p 6185943 html 运维知识各种链接 http linuxtools rst readthedocs io zh CN latest tool sar html l
  • 配置 Atlassian JIRA 插件以与 Jenkins CI 系统配合使用

    我正在尝试使用 Jenkins 配置 JIRA 插件 但收到错误 这是一个有效的 URL 但它看起来不像 JIRA 我正在尝试连接到我公司安装的 JIRA studio 即 http company jira com 我知道这个 URL 是
  • 在 PHP 中使用soap 添加 Jira 注释 [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 如何在 PHP 中使用 SOAP 在 Jira 中添加注释 soapClient
  • 查找包含带有标签的子任务的家长问题

    我有一个 JIRA 项目 我的一些任务包含标签为 needDesign 的子任务 是否可以找到包含具有该标签的子任务的所有父任务 我使用ondemand jira版本 Jira JQL 并非不提供开箱即用的功能 但是有许多扩展 JQL 的附
  • 如何将 TLS 1.0 与 Python 3.8 结合使用?

    我有一个使用 Jira 连接的代码jira module 不幸的是 Jira 服务器仅支持SSLv3 and TLS1 我知道它们是旧协议 今年年底前主办方将接受新的 但在那之前我需要我的 python 代码来使用 Jira 连接TLS1
  • Jira 用于错误跟踪和客户支持?

    我们正在考虑使用 Jira 进行错误跟踪 并将其与 Git 集成 以将错误修复与版本处理联系起来 您是否也推荐 Jira 来提供客户支持 还是我们应该寻找其他系统 例如 Zendesk 来实现此目的 我知道可以通过某种方式将 Hipchat
  • Jira:将现有的 git 分支分配给问题

    在与 STASH 连接的 JIRA 中 您可以使用 创建分支 按钮为问题创建功能分支 很高兴跟踪本期的提交 如果开发人员开始工作但不知道存在这样的问题 他就不会单击 创建分支 是否有可能将现有的 git 分支分配给问题 这里是前 Stash
  • 使用 JQL 过滤特定用户在一段时间内更新的问题

    有没有办法使用 JQL 查找特定用户在每天特定时间段更新的所有问题 或者是否有任何插件可以解决这个问题 如果更新意味着状态改变 你可以检查如下内容 status changed by user name and updated gt sta
  • JIRA 与 TortoiseSVN 集成

    谁能指定将 JIRA 与 TortoiseSVN 集成以跟踪问题详细信息的方法吗 URL部分应该指定什么URL 还需要哪些其他参数 您需要在 JIRA 方面做些什么来确保集成吗 在阅读有关该主题的 TortoiseSVN 文档时 我遇到了很
  • JIRA:查找与用户相关的所有问题

    在 JIRA 中 如何查找所有项目中与用户相关的所有问题 简单的查询搜索仅产生全文结果 即 仅涉及名称被提及的问题 而不是名称已被分配 已报告 已抄送等的问题 我在这里的目的是寻找与我相关的股票会计票据 我使用的是 JIRA 3 13 as
  • 通过php更新jira中的状态

    我正在使用我构建的电子邮件客户端来更新 jira 任务 我已经成功地通过它更改了受让人和摘要 但我似乎找不到更新状态的方法 以下是我使用的代码 resolution gt id 4 update gt transitions array r
  • 来自 cURL 请求的 RestSharp POST 请求翻译

    我正在尝试使用 RestSharp 发出 POST 请求以在 JIRA 中创建问题 而我必须使用的是一个使用 cURL 的示例 我对这两者都不够熟悉 不知道我做错了什么 这是example https developer atlassian
  • Jira:从没有主题的电子邮件创建问题和评论

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

    我希望能够过滤当前冲刺中已解决的问题 一般来说 这将用于防止在我们讨论开发人员在本次冲刺中实现了什么时出现在上一个冲刺中已解决但测试延迟 未重新开放 的问题 已关闭的问题也应该出现 但它们不是问题 就好像它们在上一个冲刺中被关闭一样 无论如
  • TFS 与 JIRA/Bamboo/SVN [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 我想从 LAN 不仅通过 IP_OF_SYNOLOGY:PORT 访问 Jira(Synology DS716+II 上的 Docker),还想通过 jira.synology.local 访问 Jira(Synology DS716+II 上的 Dock

    我正在使用 Synology NAS 类型 aDS716 II DSM 6 1 4 15217 Update 2 其上运行带有 Jira 容器的 Docker So now what I want to do I m assigned to
  • 从 JIRA 创建 Gitlab 分支

    我最近开始使用 Gitlab 并与 Jira 集成 Gitlab 和 Jira 服务器都是在我的公司环境内部自行托管的 我遇到了一个要求 我想直接从 JIRA 问题在 Gitlab 中为项目 问题创建一个分支 有可能做到吗 如果是的话怎么办

随机推荐