--- /dev/null
+#!/usr/bin/env python
+
+
+from common.envparas import export
+from common import git
+from common import buildservice
+from requests.mailer import mailer
+
+import json
+import sys
+import os
+
+envparas = ['OBS_EVENT_STRING',
+ 'OBS_OSCRC_PATH',
+ 'OBS_API_URL',
+ 'SR_ENABLE_USER',
+ 'NOREPLY_EMAIL_SENDER',
+ 'MAILINGLIST',
+ 'BCC_MAILS',
+ 'BUILD_TAG',
+ 'EMAIL_TEMPLATES_DIR',
+ 'GIT_CACHE_DIR'
+ 'GIT_URL']
+
+export(envparas, locals())
+
+def tag_info(prjdir, tag):
+
+ git.update_git_project(GIT_CACHE_DIR, prjdir, GIT_URL)
+
+ gitprj = git.Git(os.path.join(GIT_CACHE_DIR,prjdir))
+ if gitprj.find_tag(tag):
+ return gitprj.get_tagger(tag)
+
+ return {}
+
+def description_paser(description):
+
+ mapping = {"Submitter" : 'auth_email',
+ "Comments" : "comments",
+ "Tag" : "tag",
+ "Git project" : "prj",
+ "Commit" : "commit_subj"
+ }
+
+ ret_list = []
+ for section in description.split('\n\n'):
+ entry = {}
+ for line in section.split('\n'):
+ key, value = line.split(':')
+ entry[mapping[key.strip()]] = value.strip()
+
+ tag = tag_info(entry['prj'], entry['tag'])
+ entry.update(tag)
+ ret_list.append(entry)
+
+ return ret_list
+
+def request_accepted(event_fields):
+ print '====request accepted===================================='
+ print event_fields
+
+ gerrit.post_comment(prj, commit_id, msg)
+ git.create_tag('name', 'msg', commit_id)
+ invoke_mailsender()
+
+def request_rejected(event_fields):
+ print '====request rejected===================================='
+ print event_fields
+
+ gerrit.post_comment(prj, commit_id, msg)
+ invoke_mailsender()
+
+
+def request_created(event_fields):
+ print '====request created===================================='
+ print event_fields
+ gerrit.post_comment(prj, commit_id, msg)
+ invoke_mailsender()
+
+
+def notify_submiter(event_fields, desp):
+ print '====Notify the tag owner===================================='
+
+ mail_to = []
+ for entry in desp:
+ mail_to.append(entry['auth_email'])
+
+ status = True
+
+ bs = buildservice.BuildService(OBS_API_URL, OBS_OSCRC_PATH)
+
+ # step1: do reqeust policy checking
+ #if policy:
+ # need_check = reduce(lambda r, k: r or policy[k] > 0, policy.keys(), False)
+ # if need_check:
+ # rejector(event_fields, bs, policy)
+
+ # step2: email notification to mailing list
+ if MAILINGLIST:
+ status = mailer(event_fields, bs, event_fields, NOREPLY_EMAIL_SENDER,
+ MAILINGLIST, BCC_MAILS, SR_ENABLE_USER, EMAIL_TEMPLATES_DIR)
+
+ if status:
+ with open('%s.env' %(BUILD_TAG),'w') as f:
+ for a in status.keys():
+ f.write('%s=%s\n' %(a, status[a]))
+
+event = json.loads(' '.join(OBS_EVENT_STRING.split()))
+
+event_fields = event['fields']['obsEvent']
+
+if not event_fields:
+ print 'Invalid OBS event: %s' %(OBS_EVENT_STRING)
+ sys.exit(-1)
+
+desp = description_paser(event_fields['description'])
+notify_submiter(event_fields, desp)
+sys.exit(0)
+if event_fields['type'] == 'OBS_SRCSRV_REQUEST_STATECHANGE':
+ pass
+elif event_fields['type'] == 'OBS_SRCSRV_REQUEST_CREATE':
+ request_created(event_fields)
+elif event_fields['type'] == 'OBS_SRCSRV_REQUEST_ACCEPTED':
+ request_accepted(event_fields)
+
+
--- /dev/null
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Intel Corporation
+#
+# 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; version 2 of the License
+#
+# 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., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from string import Template
+import copy
+import os
+
+"""
+def := { event_name1: ( trigger, trigger ),
+ event_name2: ( trigger, ),
+ }
+trigger := { 'temp': 'template name',
+ 'cond': lambda incline function
+ 'sub': string template for subject
+ 'to': list of To:
+ 'cc': list of Cc:
+ 'from': From:
+ 'fields': list of variables to be expand in template
+ 'detail?': True/False, whether need detailed reqinfo
+ 'tgtprj': the field name in obsEvent as the target prj
+ }
+NOTE: multiple triggers need be IN STRICT ORDER
+"""
+
+IGNORE_HOME = True
+
+AUTO_REJECT_COMMENT = 'You are not a valid submitrequest sender'
+
+MAIL_TRIGGERS = {
+ 'OBS_SRCSRV_REQUEST_CREATE':
+ (
+ {
+ 'temp': 'obs_request_delpkg',
+ 'cond': lambda bs, req: req['deleteproject'] and req['deletepackage'],
+ 'sub': '${reqid}: Remove package ${deleteproject}/${deletepackage}',
+ 'to': ['mailinglist'],
+ 'cc': ['who'],
+ 'from': 'who',
+ 'fields':['description', 'deleteproject', 'deletepackage'],
+ 'detail?':False,
+ 'tgtprj': 'deleteproject',
+ },
+ {
+ 'temp': 'obs_request_maintainer',
+ 'cond': lambda bs, req: req['role'] and req['person'],
+ 'sub': '${reqid}: Maintainer request for ${targetproject}/${targetpackage}',
+ 'to': ['mailinglist'],
+ 'cc': ['who'],
+ 'from': 'who',
+ 'fields':['description', 'targetproject', 'targetpackage', 'role', 'person'],
+ 'detail?':False,
+ 'tgtprj': 'targetproject',
+ },
+ {
+ 'temp': 'obs_request_changedevel',
+ 'cond': lambda bs, req: req['origintype'] == 'change_devel',
+ 'sub': '${reqid}: Change devel of ${targetproject}/${targetpackage} to ${sourceproject}/${sourcepackage}',
+ 'to': ['mailinglist'],
+ 'cc': ['who'],
+ 'from': 'who',
+ 'fields':['description', 'targetproject', 'targetpackage', 'sourceproject', 'sourcepackage'],
+ 'detail?':False,
+ 'tgtprj': 'targetproject',
+ },
+ {
+ 'temp': 'obs_request_newpkg',
+ 'cond': lambda bs, req: bs.isNewPackage(req['targetproject'], req['targetpackage']),
+ 'sub': '${reqid}: New package ${targetproject}/${targetpackage}',
+ 'to': ['mailinglist'],
+ 'cc': ['who'],
+ 'from': 'who',
+ 'fields':['description', 'targetproject', 'targetpackage', 'sourceproject', 'sourcepackage'],
+ 'detail?':True,
+ 'tgtprj': 'targetproject',
+ },
+ {
+ 'temp': 'obs_request_create',
+ 'cond': None,
+ 'sub': '${reqid}: Changes to ${targetproject}/${targetpackage}',
+ 'to': ['mailinglist'],
+ 'cc': ['who'],
+ 'from': 'who',
+ 'fields':['description', 'targetproject', 'targetpackage', 'sourceproject', 'sourcepackage'],
+ 'detail?':True,
+ 'tgtprj': 'targetproject',
+ },
+ ),
+ 'OBS_SRCSRV_REQUEST_ACCEPTED':
+ (
+ {
+ 'temp': 'obs_request_maintainer_accept',
+ 'cond': lambda bs, req: req['state'] == 'accepted' and req['role'] and req['person'],
+ 'sub': '${reqid} accepted: ${role} request for ${targetproject}/${targetpackage}',
+ 'to': ['author', 'person'],
+ 'cc': ['mailinglist'],
+ 'from': 'sender',
+ 'fields':['comment', 'targetproject', 'targetpackage', 'role', 'person'],
+ 'detail?':False,
+ 'tgtprj': 'targetproject',
+ },
+ {
+ 'temp': 'obs_request_delpkg_accept',
+ 'cond': lambda bs, req: req['state'] == 'accepted' and req['deleteproject'] and req['deletepackage'],
+ 'sub': '${reqid} accepted: ${deleteproject}/${deletepackage} was deleted',
+ 'to': ['author'],
+ 'cc': ['mailinglist'],
+ 'from': 'sender',
+ 'fields':['comment', 'deleteproject', 'deletepackage'],
+ 'detail?':False,
+ 'tgtprj': 'deleteproject',
+ },
+ {
+ 'temp': 'obs_request_changedevel_accept',
+ 'cond': lambda bs, req: req['state'] == 'accepted' and req['origintype'] == 'change_devel',
+ 'sub': '${reqid} accepted: ${sourceproject}/${sourcepackage} is devel of ${targetproject}/${targetpackage}',
+ 'to': ['author', 'bugowners', 'devels'],
+ 'cc': ['mailinglist'],
+ 'from': 'sender',
+ 'fields':['comment', 'targetproject', 'targetpackage', 'sourceproject', 'sourcepackage'],
+ 'detail?':False,
+ 'tgtprj': 'targetproject',
+ },
+ {
+ 'temp': 'obs_request_accept',
+ 'cond': lambda bs, req: req['state'] == 'accepted',
+ 'sub': '${reqid} accepted: ${targetproject}/${targetpackage}',
+ 'to': ['author', 'bugowners', 'devels'],
+ 'cc': ['mailinglist'],
+ 'from': 'sender',
+ 'fields':['comment', 'targetproject', 'targetpackage'],
+ 'detail?':False,
+ 'tgtprj': 'targetproject',
+ },
+ ),
+ 'OBS_SRCSRV_REQUEST_STATECHANGE':
+ (
+ {
+ 'cond': lambda bs, req: req['state'] == 'declined' and req['role'] and req['person'],
+ 'temp': 'obs_request_maintainer_decline',
+ 'sub': '${reqid} declined: Request to maintain ${targetproject}/${targetpackage}',
+ 'to': ['author'],
+ 'cc': ['mailinglist'],
+ 'from': 'sender',
+ 'fields':['comment', 'targetproject', 'targetpackage', 'role', 'person'],
+ 'detail?':False,
+ 'tgtprj': 'targetproject',
+ },
+ {
+ 'cond': lambda bs, req: req['state'] == 'declined' and req['deleteproject'] and req['deletepackage'],
+ 'temp': 'obs_request_delpkg_decline',
+ 'sub': '${reqid} declined: Request to delete ${deleteproject}/${deletepackge}',
+ 'to': ['author'],
+ 'cc': ['mailinglist'],
+ 'from': 'sender',
+ 'fields':['comment', 'deleteproject', 'deletepackage'],
+ 'detail?':False,
+ 'tgtprj': 'deleteproject',
+ },
+ {
+ 'cond': lambda bs, req: req['state'] == 'declined' and req['origintype'] == 'change_devel',
+ 'temp': 'obs_request_changedevel_decline',
+ 'sub': '${reqid} declined: ${sourceproject}/${sourcepackage} as devel of ${targetproject}/${targetpackage}',
+ 'to': ['author'],
+ 'cc': ['mailinglist'],
+ 'from': 'sender',
+ 'fields':['comment', 'targetproject', 'targetpackage', 'sourceproject', 'sourcepackage'],
+ 'detail?':False,
+ 'tgtprj': 'targetproject',
+ },
+ {
+ 'cond': lambda bs, req: req['state'] == 'declined' and req['comment'] == AUTO_REJECT_COMMENT,
+ 'temp': 'obs_request_auto_reject',
+ 'sub': '${reqid} auto rejected: ${sourceproject}/${sourcepackage} to ${targetproject}/${targetpackage}',
+ 'to': ['author'],
+ 'cc': ['mailinglist'],
+ 'from': 'sender',
+ 'fields':['comment', 'targetproject', 'targetpackage', 'sourceproject', 'sourcepackage'],
+ 'detail?':False,
+ 'tgtprj': 'targetproject',
+ },
+ {
+ 'cond': lambda bs, req: req['state'] == 'declined',
+ 'temp': 'obs_request_decline',
+ 'sub': '${reqid} declined: ${sourceproject}/${sourcepackage} to ${targetproject}/${targetpackage}',
+ 'to': ['author'],
+ 'cc': ['mailinglist'],
+ 'from': 'sender',
+ 'fields':['comment', 'targetproject', 'targetpackage', 'sourceproject', 'sourcepackage'],
+ 'detail?':False,
+ 'tgtprj': 'targetproject',
+ },
+ {
+ 'cond': lambda bs, req: req['state'] == 'revoked' and req['role'] and req['person'],
+ 'temp': 'obs_request_maintainer_revoke',
+ 'sub': '${reqid} revoked: Request to maintain ${targetproject}/${targetpackage}',
+ 'to': ['mailinglist'],
+ 'cc': [],
+ 'from': 'who',
+ 'fields':['comment', 'targetproject', 'targetpackage', 'role', 'person'],
+ 'detail?':False,
+ 'tgtprj': 'targetproject',
+ },
+ {
+ 'cond': lambda bs, req: req['state'] == 'revoked' and req['deleteproject'] and req['deletepackage'],
+ 'temp': 'obs_request_delpkg_revoke',
+ 'sub': '${reqid} revoked: Request to delete ${deleteproject}/${deletepackage}',
+ 'to': ['mailinglist'],
+ 'cc': [],
+ 'from': 'who',
+ 'fields':['comment', 'deleteproject', 'deletepackage'],
+ 'detail?':False,
+ 'tgtprj': 'deleteproject',
+ },
+ {
+ 'cond': lambda bs, req: req['state'] == 'revoked' and req['origintype'] == 'change_devel',
+ 'temp': 'obs_request_changedevel_revoke',
+ 'sub': '${reqid} revoked: Change devel of ${targetproject}/${targetpackage}',
+ 'to': ['mailinglist'],
+ 'cc': [],
+ 'from': 'who',
+ 'fields':['comment', 'targetproject', 'targetpackage', 'sourceproject', 'sourcepackage'],
+ 'detail?':False,
+ 'tgtprj': 'targetproject',
+ },
+ {
+ 'cond': lambda bs, req: req['state'] == 'revoked',
+ 'temp': 'obs_request_revoke',
+ 'sub': '${reqid} revoked: Changes to ${targetproject}/${targetpackage}',
+ 'to': ['mailinglist'],
+ 'cc': [],
+ 'from': 'who',
+ 'fields':['comment', 'targetproject', 'targetpackage'],
+ 'detail?':False,
+ 'tgtprj': 'targetproject',
+ },
+ ),
+ }
+
+USERDATA_CACHE = {}
+
+def logger(level, msg):
+ print level, msg
+
+def _get_reqinfo(bs, rid, details):
+ try:
+ return bs.genRequestInfo(str(rid), show_detail=details)
+ except Exception, e:
+ logger('error', 'failed to get info for req: %s, abort!' %rid)
+ logger('error', str(e))
+ return ''
+
+def _get_userinfo(bs, uid):
+ try:
+ if uid in USERDATA_CACHE:
+ realname, email = USERDATA_CACHE[uid]
+ else:
+ realname, email = bs.getUserData(uid, "realname", "email")
+ USERDATA_CACHE[uid] = (realname, email)
+ if realname == '-':
+ realname = uid
+ return realname, '%s <%s>' % (realname, email)
+ except:
+ return uid, ''
+
+def _expand_addr(bs, req, mails, ml):
+ expanded = []
+
+ for m in set(mails):
+ if m == 'mailinglist':
+ expanded.append(ml)
+ elif m == 'bugowners':
+ bugowners = bs.getPackagePersons(req['targetproject'], req['targetpackage'], 'bugowner')
+ for bugowner in bugowners:
+ expanded.append(_get_userinfo(bs, bugowner)[1])
+ elif m == 'devels':
+ devel = bs.getPackageDevel(req['targetproject'], req['targetpackage'])
+
+ if not devel:
+ devel = bs.getProjectDevel(req['targetproject'])
+
+ if devel:
+ maintainers = bs.getProjectPersons(devel[0], 'maintainer')
+ for maintainer in maintainers:
+ expanded.append(_get_userinfo(bs, maintainer)[1])
+ elif m in req:
+ expanded.append(_get_userinfo(bs, req[m])[1])
+ else:
+ # some real mailaddrs
+ expanded.append(m)
+
+ # uniquy -> filter out empty -> list
+ return [i for i in set(expanded) if i]
+
+def _is_valid_submitter(temp, author, enabled_users):
+ if temp in ('obs_request_newpkg', 'obs_request_create'):
+ if enabled_users:
+ if author not in enabled_users:
+ return False
+
+ return True
+
+def mailer(request, bs, wi, noreply_sender, ml, bccs,
+ sr_enabled_users = None, templates_dir = '.'):
+ """ Sending mail to mailing list for different kinds of reqs
+ """
+
+ if request['type'] not in MAIL_TRIGGERS.keys():
+ return False
+
+ rid = request['id']
+
+ for ev, triggers in MAIL_TRIGGERS.iteritems():
+ if request['type'] != ev:
+ continue
+
+ for tri in triggers:
+ if not tri['cond'] or tri['cond'](bs, request):
+ tgtprj = request[tri['tgtprj']]
+ if tgtprj is None:
+ logger('info', 'ignore requests for empty targetproject: %s' % ev)
+ return False
+
+ if IGNORE_HOME and tgtprj.startswith('home'):
+ logger('info', 'ignore requests for home project: %s' % ev)
+ return False
+
+ if not _is_valid_submitter(tri['temp'], request['author'], sr_enabled_users):
+ bs.reqDecline(rid, msg=AUTO_REJECT_COMMENT)
+ return False
+
+ logger('info', 'sending mail for %s %s' %(ev, tri['temp']))
+
+ tos = copy.copy(tri['to'])
+ ccs = copy.copy(tri['cc'])
+
+ reqinfo = _get_reqinfo(bs, rid, tri['detail?'])
+ wi['reqinfo'] = reqinfo
+
+ if tgtprj.startswith('devel:'):
+ for alist in (tos, ccs):
+ maintainers = bs.getProjectPersons(tgtprj, 'maintainer')
+ if 'mailinglist' in alist:
+ # if submitter is a maintainer, only send to other maintainers
+ if request['author'] in maintainers:
+ alist.remove('mailinglist')
+ maintainers.remove(request['author'])
+
+ for maintainer in maintainers:
+ alist.append(_get_userinfo(bs, maintainer)[1])
+
+ mailto_list = _expand_addr(bs, request, tos, ml)
+ mailcc_list = _expand_addr(bs, request, ccs, ml)
+
+ has_noreply = False
+ for alist in (mailto_list, mailcc_list):
+ for pair in alist:
+ if noreply_sender in pair:
+ alist.remove(pair)
+ has_noreply = True
+
+ if has_noreply:
+ if ml in mailcc_list:
+ mailcc_list.remove(ml)
+ if ml not in mailto_list:
+ mailto_list.insert(0, ml)
+
+ wi['To'] = mailto_list
+ wi['Cc'] = mailcc_list
+
+ if bccs:
+ wi['Bcc'] = bccs
+
+ if tri['from']:
+ realname = _get_userinfo(bs, request[tri['from']])[0]
+ else:
+ realname = 'Tizen OBS'
+ wi['realname'] = realname
+ wi['From'] = '%s <%s>' % (realname, noreply_sender)
+
+
+ first_to = tos[0]
+ if first_to == 'mailinglist':
+ wi['receipt'] = 'List'
+ else:
+ wi['receipt'] = _get_userinfo(bs, request[first_to])[0]
+
+ wi['realname'] = realname
+
+ wi['template'] = tri['temp']
+ from string import Template
+ wi['subject'] = Template(tri['sub']).safe_substitute(request, reqid=str(rid))
+
+ # other items from obs_event
+ for var in tri['fields']:
+ wi[var] = request[var]
+
+ break
+
+ if 'template' in wi.keys():
+ template_str = file(os.path.join(templates_dir, wi['template'])).read()
+ msg = []
+ try:
+ from Cheetah.Template import Template
+ template = Template(template_str, searchList = wi)
+ template.msg = "\n".join(msg)
+ body = str(template)
+ except ImportError:
+ from string import Template
+ template = Template(template_str)
+ body = template.safe_substitute(wi, msg="\n".join(msg))
+ wi['body'] = body.replace('\n','\\n')
+
+
+ return wi
+