這個(gè)腳本實(shí)現(xiàn)了:
- 按指定的條件搜索出對(duì)應(yīng)的Jira列表,并將這些Jira的所有信息讀取出來;
- 提取出有效信息,并按照寫好的html模板將信息填入其中;
- 將該郵件發(fā)給Jira列表里包括的assignee人員和配置的默認(rèn)收件人;
Python-jira自動(dòng)化實(shí)現(xiàn)代碼
-
獲取Jira內(nèi)容
# encoding=utf-8
# ----------------------------------------
# 語言:Python2.7
# 功能:jira模板,含登錄和獲取列表
# ----------------------------------------
import base64
import json
from jira import JIRA
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
JIRA_SERVER = 'http://jira.n.company.com' # jira服務(wù)器
JIRA_FIELDS = 'issuetype,issuekey,summary,priority,status,resolution,assignee,reporter,created,duedate,updated'
MAX_RESULTS = 100 # 最多讀取100條記錄
# jira登錄
def _login():
login_info = json.load(open('../configurations/login.conf')) # 加載登錄信息
# 需要先解碼再使用
login_info['user'] = base64.decodestring(login_info['user'])
login_info['pwd'] = base64.decodestring(login_info['pwd'])
basic_auth = (login_info['user'], login_info['pwd'])
try:
jira = JIRA(server=JIRA_SERVER, basic_auth=basic_auth)
except Exception, e:
print "Jira登錄異常:" + e.message
else:
return jira
# 根據(jù)條件查找并返回issues
def get_issues(conditions):
jira = _login()
dict_list = []
conditions = conditions.split(';') # 支持多個(gè)條件組合查詢,以;分割
for condition in conditions:
issues = jira.search_issues(condition, maxResults=MAX_RESULTS, fields=JIRA_FIELDS)
for issue in issues:
issue_type = str(issue.fields.issuetype)
issue_key = str(issue)
summary = str(issue.fields.summary.encode('utf-8'))
priority = str(issue.fields.priority)
status = str(issue.fields.status)
resolution = str(issue.fields.resolution)
assignee = str(issue.fields.assignee)
reporter = str(issue.fields.reporter)
created = str(issue.fields.created)[0:19] # 截取時(shí)間
due_date = str(issue.fields.duedate)[0:19]
updated = str(issue.fields.updated)[0:19]
issue_link = 'http://jira.n.company.com/browse/' + issue_key
address = str(issue.fields.assignee.emailAddress)
display_name = str(issue.fields.assignee.displayName)
# 創(chuàng)建jira字典并返回
issue_dict = {
'issuetype': issue_type,
'issuekey': issue_key,
'summary': summary,
'priority': priority,
'status': status,
'resolution': resolution,
'assignee': assignee,
'reporter': reporter,
'created': created,
'duedate': due_date,
'updated': updated,
'issuelink': issue_link,
'address': address,
'displayName': display_name
}
dict_list.append(issue_dict)
return dict_list
# 按照assignee排列搜索出issues,返回字典格式
def get_issues_by_assignee(conditions):
sorted_issues = get_issues(conditions)
print sorted_issues
print "get issues by assignee"
issues_by_assignee = {} # key:assignee,value:jiras of assignee
for issue in sorted_issues:
assignee = issue['assignee']
if assignee in issues_by_assignee.keys():
issues_by_assignee[assignee].append(issue)
else:
temp_dict = []
temp_dict.append(issue)
issues_by_assignee[assignee] = temp_dict
print str(issues_by_assignee)
if issues_by_assignee is None:
print "issues_by_assignee is null"
return issues_by_assignee
# 獲取去重后的收信人列表
def get_cc_address(jira_dict):
cc_address = ''
for jira in jira_dict:
address = jira['address']
if address not in cc_address:
cc_address += address + ";"
return cc_address
# 獲取收信人姓名
def get_cc_assignees(jira_dict):
cc_assignees = ''
for jira in jira_dict:
assignee = jira['assignee']
if assignee not in cc_assignees:
cc_assignees += "@" + jira['displayName'] + " " # jira里的姓名以@分隔
return cc_assignees
-
發(fā)郵件
# encoding=utf-8
# ----------------------------------------
# 語言:Python2.7
# 功能:郵件模板
# ----------------------------------------
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from jira_module import get_cc_address, get_cc_assignees
import json
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
DEFAULT_SENDER = 'suyongsheng@163.com' # 默認(rèn)發(fā)送者
# 讀取郵件內(nèi)容配置
def get_email_conf(conf_name):
try:
email_conf = json.load(open(conf_name))
except Exception, e:
print "讀取Json文件異常:" + e.message
else:
return email_conf
def get_t_table(jira_dict):
t_table = ''
for jira in jira_dict:
email_temp = '''
<tr>
<td><span class="check">%s</span></td>
<td><a href=%s class="check">%s</a></td>
<td><span class="check">%s</span></td>
<td><span class="check">%s</span></td>
<td><span class="check">%s</span></td>
<td><span class="check">%s</span></td>
<td><span class="check">%s</span></td>
<td><span class="check">%s</span></td>
<td><span class="check">%s</span></td>
</tr>
''' % (jira['issuetype'],jira['issuelink'],jira['issuekey'],jira['summary'],jira['priority'],
jira['assignee'],jira['reporter'],jira['created'],jira['updated'],jira['duedate'])
t_table += email_temp
return t_table
# email 模塊
def send_email(email_dict, jira_dict):
if email_dict is None:
print "讀取到的email配置為空"
return
print "[" + email_dict['subject'] + "] 正在構(gòu)造郵件,請(qǐng)稍等..."
if email_dict['content']:
content = email_dict['content']
else:
content = '[默認(rèn)提示]以下Jira需要被關(guān)注'
t_table = get_t_table(jira_dict)
cc_address = get_cc_address(jira_dict)
cc_assignees = get_cc_assignees(jira_dict)
subject = email_dict['subject']
receiver = cc_address + email_dict['defaultReceiver'] # 將爬取到的assignee添加到收件人列表
to_addrs = receiver.split(';')
# 構(gòu)造郵件對(duì)象MIMEMultipart對(duì)象
msg = MIMEMultipart('mixed')
msg['Subject'] = subject
# 收件人為多個(gè)收件人,通過join將列表轉(zhuǎn)換為以,為間隔的字符串
msg['To'] = ",".join(to_addrs)
# 構(gòu)造html
html = """
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Jira自動(dòng)匯總</title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
body{
font: italic 20px Georgia, serif;
letter-spacing: normal;
background-color: #f0f0f0;
}
#content{
width: 800px;
padding: 40px;
}
#table1{
font: bold 16px/1.4em "Trebuchet MS", sans-serif;
}
#table1 thead th{
padding: 15px;
border: 1px solid #93CE37;
border-bottom: 3px solid #9ED929;
text-shadow: 1px 1px 1px #568F23;
color: #fff;
background-color: #9DD929;
border-radius: 5px 5px 0px 0px;
}
#table1 thead th:empty{
background-color: transparent;
border: none;
}
#table1 tbody th{
padding: 0px 10px;
border: 1px solid #93CE37;
border-right: 3px solid #9ED929;
text-shadow: 1px 1px 1px #568F23;
color: #666;
background-color: #9DD929;
border-radius: 5px 0px 0px 5px;
}
#table1 tbody td{
padding: 10px;
border: 2px solid #E7EFE0;
text-align: center;
text-shadow: 1px 1px 1px #fff;
color: #666;
background-color: #DEF3CA;
border-radius: 2px;
}
</style>
</head>
<body>
<b>原因 : </b>%s<br>
<b>名單 : </b><span style="color:blue;font-weight:bold"><b>%s</b></span><br/><br/>
請(qǐng)?jiān)诹型瑢W(xué)及時(shí)關(guān)注并更新 jira狀態(tài).( 本郵件為自動(dòng)發(fā)送,請(qǐng)勿回復(fù) )
<div id="content">
<table id="table1">
<thead>
<tr>
<th scope="col" abbr="Starter">Issue Type</th>
<th scope="col" abbr="Starter">Key</th>
<th scope="col" abbr="Medium">Summary</th>
<th scope="col" abbr="Business">Priority</th>
<th scope="col" abbr="Deluxe">Assignee</th>
<th scope="col" abbr="Deluxe">Reporter</th>
<th scope="col" abbr="Deluxe">Created</th>
<th scope="col" abbr="Deluxe">Updated</th>
<th scope="col" abbr="Deluxe">Due Date</th>
</tr>
</thead>
<tbody>
%s
</tbody>
</table>
</div>
<address>
Written by <a href="mailto:suyongsheng@163.com">Su Yongsheng</a>.<br>
Visit me at : Xiaobailou 203<br>
</address>
</body>
</html>
""" % (content, cc_assignees, t_table)
text_html = MIMEText(html, 'html', 'utf-8')
msg.attach(text_html)
try:
smtp = smtplib.SMTP()
smtp.connect("mail.srv")
smtp.sendmail(DEFAULT_SENDER, to_addrs, msg.as_string())
smtp.close()
print "[%s] send email success" % subject
except Exception, e:
print "Error:[%s] unable to send email becauseof " % subject + e.message
# 報(bào)警郵件
def send_alarm_email(errMsg):
subject = 'Jira自動(dòng)化報(bào)警郵件'
receiver = 'suyongsheng@163.com'
to_addrs = receiver.split(';')
msg = MIMEMultipart('mixed')
msg['Subject'] = subject
msg['To'] = ",".join(to_addrs)
# 構(gòu)造html
html = """
<!DOCTYPE html>
<html>
<body>
<h1 id="blink"><b>Jira郵件發(fā)送異常</b></h1>
<p><b><font size="5">報(bào)警原因:%s</font></b></p>
<script language="javascript">
function changeColor(){
var color="#f00|#000";
color=color.split("|");
document.getElementById("blink").style.color=color[parseInt(Math.random() * color.length)];
}
setInterval("changeColor()",200);
</script>
</body>
</html>
""" % (errMsg)
text_html = MIMEText(html, 'html', 'utf-8')
msg.attach(text_html)
try:
smtp = smtplib.SMTP()
smtp.connect("mail.srv")
smtp.sendmail(DEFAULT_SENDER, to_addrs, msg.as_string())
smtp.close()
print "[%s] send alarm email success" % subject
except Exception, e:
print "Error:[%s] unable to send alarm email becauseof " % subject + e.message
-
獲取日期
# encoding=utf-8
# ----------------------------------------
# 語言:Python2.7
# 功能:獲取日期&時(shí)間
# ----------------------------------------
import datetime
NOW = datetime.datetime.now()
# 獲取當(dāng)前月份
def get_month():
month = NOW.month
return month
# 獲取當(dāng)前日期
def get_day():
day = NOW.day
return day
# 獲取當(dāng)前小時(shí)
def get_hour():
hour = NOW.hour
return hour
# 獲取當(dāng)前分鐘
def get_minute():
minute = NOW.minute
return minute
# 獲取當(dāng)前星期
def get_weekday():
weekday = NOW.weekday() + 1 # 1~7:分別代表周一~周日
return int(weekday)
-
從zookeeper讀取配置
# encoding=utf-8
# ----------------------------------------
# 語言:Python2.7
# 功能:從zookeeper讀取配置
# 位置:/company/cash/jira/config
# ----------------------------------------
import zookeeper
from data_module import get_hour
# 獲取zookeeper配置
def get_zk_data():
zk = zookeeper.init("zk.staging.srv:8080") # 初始化zookeeper
try:
zk_children = zookeeper.get_children(zk, "/company/cash/jira")
# 如果test節(jié)點(diǎn)存在,則不會(huì)運(yùn)行config節(jié)點(diǎn),方便對(duì)新配置進(jìn)行測試
if 'test' in zk_children:
zk_test = zookeeper.get(zk, "/company/cash/jira/test")
if zk_test[0] is not '':
print '測試節(jié)點(diǎn)不為空,將使用測試節(jié)點(diǎn)的配置...'
return zk_test[0]
except Exception, e:
print e.message
# 目前只判斷了test和config兩個(gè)節(jié)點(diǎn),后期如果有較多人使用,則添加掃描其他節(jié)點(diǎn)
zk_config = zookeeper.get(zk, "/company/cash/jira/config")
zookeeper.close(zk)
return zk_config[0]
# 清空test配置,保證每天定時(shí)能夠順利執(zhí)行
def del_test_data():
hour = int(get_hour())
zk = zookeeper.init("zk.staging.srv:8080")
try:
if 0 <= hour <= 7: # 00:00~08:00之間的test配置會(huì)被清空
zk_children = zookeeper.get_children(zk, "/company/cash/jira")
if 'test' in zk_children:
zk_test = zookeeper.get(zk, "/company/cash/jira/test")
# 如果test節(jié)點(diǎn)存在且不為空,則清空配置
if zk_test[0] is not '':
zookeeper.set(zk, "/company/cash/jira/test", "")
except Exception, ex:
print ex.message
zookeeper.close
-
配置格式
{
"reward_system": {
"key": "reward_system",
"subject": "獎(jiǎng)懲制度-Jira匯總",
"defaultReceiver": "cashtest@163.com",
"conditions": "type in (Bug) AND project in (SONG, FSK, HQ, HLTEL) AND status not in (Closed,Resolved) AND component in (現(xiàn)金) AND (priority = Blocker AND created <= -4d OR priority = Critical AND created <= -12d OR priority = Major AND created <= -115d OR priority = Minor AND created <= -175d)",
"content": "涉及到獎(jiǎng)懲制度, 出現(xiàn)在下面 Jira列表的各位請(qǐng)及時(shí)更新.",
"singleOrBatch": "batch",
"triggerDay": "0",
"status": "VALID",
"memo": "獎(jiǎng)懲制度-Jira匯總铡买,2018-07-04開始此任務(wù)"
}
}
流程:開始任務(wù) - 從zookeeper讀取配置 - 自動(dòng)登錄Jira并根據(jù)搜索條件獲取Jira列表 - 爬取Jira內(nèi)容并組裝郵件 - 發(fā)郵件 - 結(jié)束
完整代碼可參考Github :Jira自動(dòng)化