JIRA自動(dòng)化教程(Python爬蟲)

這個(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)化

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市台谢,隨后出現(xiàn)的幾起案子寻狂,更是在濱河造成了極大的恐慌,老刑警劉巖朋沮,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡樊拓,警方通過查閱死者的電腦和手機(jī)纠亚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來筋夏,“玉大人蒂胞,你說我怎么就攤上這事√跖瘢” “怎么了骗随?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赴叹。 經(jīng)常有香客問我鸿染,道長,這世上最難降的妖魔是什么乞巧? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任涨椒,我火速辦了婚禮,結(jié)果婚禮上绽媒,老公的妹妹穿的比我還像新娘蚕冬。我一直安慰自己,他們只是感情好是辕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布囤热。 她就那樣靜靜地躺著,像睡著了一般获三。 火紅的嫁衣襯著肌膚如雪旁蔼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天石窑,我揣著相機(jī)與錄音牌芋,去河邊找鬼。 笑死松逊,一個(gè)胖子當(dāng)著我的面吹牛躺屁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播经宏,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼犀暑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了烁兰?” 一聲冷哼從身側(cè)響起耐亏,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沪斟,沒想到半個(gè)月后广辰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年择吊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了李根。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡几睛,死狀恐怖房轿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情所森,我是刑警寧澤囱持,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站焕济,受9級(jí)特大地震影響纷妆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吼蚁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一凭需、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧肝匆,春花似錦粒蜈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至能曾,卻和暖如春度硝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寿冕。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來泰國打工蕊程, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人驼唱。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓藻茂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親玫恳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辨赐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,389評(píng)論 0 5
  • 肯定有方法。 而且這種方法一定會(huì)帶著一點(diǎn)點(diǎn)個(gè)性化京办,而恰恰是這一點(diǎn)點(diǎn)就令到別人無從模仿掀序。 橘過淮則為枳,越過某種界限...
    春風(fēng)十里木有一路桃花閱讀 192評(píng)論 0 3
  • 今天把老家搞了大掃除惭婿,全部雜物清理干凈不恭。 并且重新?lián)Q了家具叶雹,床,衣柜县袱,消毒柜全都換了浑娜,家里煥然一新佑力,一些不做用的東...
    安福閱讀 201評(píng)論 0 1
  • 一式散、印象最深刻是三件事 1、由于要聽課打颤,同學(xué)們今天坐的格外整齊暴拄。上課期間也沒人玩手機(jī),課堂秩序良好编饺。 2乖篷、老師今天...
    小沐Julia閱讀 223評(píng)論 1 0
  • 在這個(gè)社會(huì)上秽誊,我們常常感到世態(tài)炎涼,經(jīng)常被人利用又被踐踏锅论,因此我們?nèi)菀资軅?正所謂:易漲易落山溪水讼溺,易反易覆小人...
    饑者求食閱讀 669評(píng)論 2 18