refactored submitobs script
authorLin Yang <lin.a.yang@intel.com>
Thu, 21 Mar 2013 09:05:24 +0000 (17:05 +0800)
committerGerrit Code Review <gerrit2@otctools.jf.intel.com>
Mon, 25 Mar 2013 07:29:50 +0000 (00:29 -0700)
1. seperate main function into several small functions
2. pylint check
3. get rid of global parameters

Change-Id: Iaa20dbb32c87b443b8b979e2a13c626a1220a008
Signed-off-by: Lin Yang <lin.a.yang@intel.com>
job_submitobs.py

index 4228e9f..392906d 100755 (executable)
@@ -5,12 +5,11 @@
 """
 
 import os
+import sys
 import tempfile
-import glob
 import shutil
 import re
 from time import sleep
-import datetime
 import random
 
 # internal module
@@ -19,256 +18,292 @@ from common import utils
 from common.git import Git, clone_gitproject
 from common import obspkg
 from common import mapping
-from common.envparas import export
-from common import errors
-from common import mysql
+from common.gerritevent import get_gerrit_event
 from common import gerrit 
 from common.send_mail import prepare_mail
-from common.gerrit import is_ref_deleted
 
 import gbp.rpm
 
-envparas = ['GERRIT_EVENT_TYPE',
-            'GERRIT_PROJECT',
-            'GERRIT_BRANCH',
-            'GERRIT_SSHPORT',
-            'GERRIT_USERNAME',
-            'GERRIT_HOSTNAME',
-            'GERRIT_CHANGE_NUMBER',
-            'GERRIT_PATCHSET_NUMBER',
-            'GERRIT_PATCHSET_REVISION',
-            'GERRIT_OLDREV',
-            'GERRIT_NEWREV',
-            'GERRIT_REFNAME',
-            'WORKSPACE',
-            'JENKINS_HOME',
-            'OBS_URL',
-            'OBS_API_URL',
-            'OBS_API_USERNAME',
-            'OBS_API_PASSWD',
-            'MYSQL_HOSTNAME',
-            'MYSQL_USERNAME',
-            'MYSQL_PASSWORD',
-            'BUILD_TAG',
-            'MYSQL_DB_NAME',
-            'GIT_CACHE_DIR',
-            'MAPPING_PRJ',
-            'RPMLINT_PRJ',
-            'NOREPLY_EMAIL_SENDER']
-export(envparas, locals())
-GIT_URL = 'ssh://%s@%s:%s' % (GERRIT_USERNAME, GERRIT_HOSTNAME, GERRIT_SSHPORT)
-
-ret = { 'rc' : {'success' : 0, 'failure' : 0, 'retry' : 1},
-        'dbstate': {'success' : 'TRIGGER_SUCCESS',
-                    'failure' : 'TRIGGER_FAILURE',
-                    'retry' : 'TRIGGER_RETRY'},
-        'dbtable' : {'CHANGE_MERGED' : 'ChangeMerged_Event',
-                     'REF_UPDATED' : 'RefUpdated_Event'},
-        'dbkey' : {'CHANGE_MERGED' : {'changeNum' : GERRIT_CHANGE_NUMBER,
-                                      'patchsetNum' : GERRIT_PATCHSET_NUMBER},
-                  'REF_UPDATED' : {'oldRev' : GERRIT_OLDREV,
-                                   'newRev' : GERRIT_NEWREV}},
-      }
-
-WRONG_VERSION_MSG = 'The tag %s pushed, which means you want to submit commit %s in %s branch to OBS, but this commit does NOT exist in %s branch. please use correct branch name as version in tag name submit/{version}/{date.time}. Suggest to use "gbs submit" to trigger submission, or use following command to create tag "git tag submit/${version}/$(date --utc +%%Y%%m%%d.%%H%%M%%S) -m "****" ".'
-WRONG_DATE_MSG = 'The tag %s pushed, but time %s does NOT follow correct format. You can use shell command "date --utc +%%Y%%m%%d.%%H%%M%%S" to generate it, like 20120801.083113. Suggest to use "gbs submit" to trigger submission, or use following command to create tag "git tag submit/${version}/$(date --utc +%%Y%%m%%d.%%H%%M%%S) -m "****" ".'
-UNDER_REVIEW_MSG = 'The tag %s pushed, but the commit %s is still under review in gerrit. After reviewer accpet this commit, it will be submitted to OBS corresponding project.'
-WRONG_COMMIT_MSG = 'The tag %s pushed, but the commit %s does NOT exist in git tree or gerrit open change. Please make sure the commit has been pushed to gerrit and correct magical ref refs/for/branch.'
-UNKNOWN_FORMAT_MSG = 'The tag %s pushed, but unknown tag format, please follow the format submit/{version}/{date.time}. Suggest to use "gbs submit" to trigger submission, or use following command to create tag "git tag submit/${version}/$(date --utc +%%Y%%m%%d.%%H%%M%%S) -m "****" ".'
-NOT_ANNOTATED_MSG = 'Tag %s should be annotated tag. Suggest to use "gbs submit" to trigger submission, or use following command to create tag "git tag submit/${version}/$(date --utc +%%Y%%m%%d.%%H%%M%%S) -m "****" ".'
-NO_MAPPING_MSG = 'The tag %s pushed, but the change for %s branch will not be submitted to OBS according configuration in gerrit scm/git-obs-mapping project. If needed, please modify scm/git-obs-mapping to enable submission to OBS.'
+WRONG_VERSION_MSG = '- The tag means you want to submit commit %s in %s branch'\
+                    ' to OBS, but this commit does NOT exist in %s branch. '\
+                    'Please use correct branch name as version in tag name '\
+                    'submit/{version}/{date.time}.'
+WRONG_DATE_MSG = '- The date %s in tag does NOT follow correct format. You can'\
+                 ' use shell command "date --utc +%%Y%%m%%d.%%H%%M%%S" to '\
+                 'generate it, like 20120801.083113.'
+UNDER_REVIEW_MSG = '- The commit %s is still under review in gerrit. After '\
+                   'reviewer accpet this commit, it will be submitted to OBS '\
+                   'corresponding project.'
+WRONG_COMMIT_MSG = '- The commit %s tag attached does NOT exist in git tree or'\
+                   ' gerrit open change. Please make sure the commit has been '\
+                   'pushed to gerrit and correct magical ref refs/for/branch.'
+UNKNOWN_FORMAT_MSG = '- Unknown tag format, please follow the format '\
+                     'submit/{version}/{date.time}.'
+NOT_ANNOTATED_MSG = '- Tag should be annotated tag.'
+SUGGESTION = 'Suggest to use "gbs submit" to trigger submission, or use '\
+             'following command to create tag "git tag '\
+             'submit/${version}/$(date --utc +%%Y%%m%%d.%%H%%M%%S) -m "****" ".'
 TITLE_FAILED = '[Submit Request Failed]: tag: %s in %s'
-TITLE_PENDING = '[Submit Request Pending]: tag: %s in %s'
+EMAIL_FOOTER = '\n\n--------------------------------------------------------\n'\
+               'Automatically generated by backend service.\n'\
+               'Please DO NOT Reply!'
 
-def feedback(msg, tag, tagger, mygerrit):
+def send_mail(title, msg, receiver):
     """ post message back to gerrit and send mail to tag owner """
-    # current disable post comment to gerrit
-    #mygerrit.review(commit = GERRIT_PATCHSET_REVISION, message = msg)
-    if tagger.has_key('author') and tagger.has_key('email'): 
-        msg = 'Hi, %s,\n\n' % tagger['author'] + msg + '\n\n----------------------------------------------------------------\nAutomatically generated by backend service.\nPlease DO NOT Reply!'
-        prepare_mail("%s.mail.env" % random.random(), TITLE_FAILED % (tag, GERRIT_PROJECT), msg, NOREPLY_EMAIL_SENDER, tagger['email'])
-
-def end(result = 'success'):
-    print 'execute result: %s' % result
-    db = mysql.Database(MYSQL_HOSTNAME, MYSQL_USERNAME, MYSQL_PASSWORD, MYSQL_DB_NAME)
-    # cleanup workspace
-    shutil.rmtree(tmpdir)
-    # update corresponding record in mysql db
-    db.update(ret['dbtable'][GERRIT_EVENT_TYPE], {'state' : ret['dbstate'][result]}, ret['dbkey'][GERRIT_EVENT_TYPE])
-    exit(ret['rc'][result])
-
-def check_tag_format(tag, git, gerrit):
-    """check whether tag follow proper format"""
-    global GERRIT_BRANCH
-
-    commitid = git.rev_parse(tag)
-    result = {}
-    if tag.find('/',len('submit/')) != -1:
-        branch = tag[len('submit/'):tag.rfind('/')]
-        date = tag[tag.rfind('/')+1:]
-        print 'check tag', branch, date
-        p = re.compile('^[0-9]{8}\.[0-9]{6}$')
-        if p.match(date):
+
+    if receiver.has_key('author') and receiver.has_key('email'):
+        msg = 'Hi, %s,\n\n' % receiver['author'] + msg + EMAIL_FOOTER
+        prepare_mail("%s.mail.env" % random.random(), title, msg,
+                     os.getenv('NOREPLY_EMAIL_SENDER'), receiver['email'])
+
+def parse_submit_tag(tag):
+    """parse info from submit tag name"""
+
+    branch = None
+    date = None
+
+    if tag.startswith('submit/'):
+        pos = tag.find('/', len('submit/'))
+        if pos != -1:
+            branch = tag[len('submit/'):pos]
             if branch == 'trunk':
                 branch = 'master'
-            branches = git.branch_contains(tag)
-            print 'branches', branches
-            if branches:
-                # the tagged commit has been merged on gerrit
-                if branch not in branches:
-                    # The tag is on wrong branch
-                    result['title'] =  TITLE_FAILED % (tag, GERRIT_PROJECT)
-                    result['message'] = WRONG_VERSION_MSG % (tag, commitid, branch, branch)
+            date = tag[pos+1:]
+
+    return branch, date
+
+def find_submit_tag(event, mygit):
+    """find the corresponding submit tag for this event"""
+
+    if event['event_type'] == 'ref-updated':
+        tag = event['refname'][len('refs/tags/'):]
+        event['branch'] = parse_submit_tag(tag)[0]
+        event['patchset_revision'] = mygit.rev_parse(tag)
+    elif event['event_type'] == 'change-merged':
+        # for chanage-merged, search submit tag on this commit
+        branch = event['branch']
+        if event['branch'] == 'master':
+            branch = 'trunk'
+        tag = mygit.describe('--exact-match', '--match', 'submit/%s/*' %
+                branch, event['patchset_revision'])
+
+    return tag
+
+def check_tag_format(git, mygerrit, event, tag):
+    """check whether tag follow proper format"""
+
+    branch, date = parse_submit_tag(tag)
+    message = []
+
+    # check tag name format
+    if branch and date:
+        # check date format
+        pattern = re.compile('^[0-9]{8}\.[0-9]{6}$')
+        if not pattern.match(date):
+            message.append(WRONG_DATE_MSG % date)
+
+        # check branch format
+        branches = git.branch_contains(tag)
+        if branches:
+            # the tagged commit has been merged on gerrit
+            if branch not in branches:
+                # tag is on wrong branch
+                message.append(WRONG_VERSION_MSG % (event['patchset_revision'],
+                                                    branch, branch))
+        else:
+            # The tagged commit doesn't exist in git tree
+            cmd = '--current-patch-set status: open project: %s commit: %s' % \
+                      (event['project'], event['patchset_revision'])
+            gerritinfo = mygerrit.query(cmd)
+            if len(gerritinfo) == 1 and gerritinfo[0].has_key('number') and gerritinfo[0].has_key('currentPatchSet'):
+                if gerritinfo[0]['branch'] == branch:
+                    # the tagged commit still open, abort submit this time
+                    message.append(UNDER_REVIEW_MSG % event['patchset_revision'])
                 else:
-                    GERRIT_BRANCH = branch
-                    print 'submit tag : %s, on branch %s'  % (tag, branch)
+                    # tag is on wrong branch
+                    message.append(WRONG_VERSION_MSG % (event['patchset_revision'], branch, branch))
             else:
-                # The tagged commit doesn't exist in git tree
-                gerritinfo = gerrit.query('--current-patch-set status: open project: %s commit: %s' % (GERRIT_PROJECT, commitid))
-                if len(gerritinfo) == 1 and gerritinfo[0].has_key('number') and gerritinfo[0].has_key('currentPatchSet'):
-                    if gerritinfo[0]['branch'] == branch:
-                        # The tagged commit still open, abort submit this time
-                        print '\nThis change is still open in gerrit, exit now'
-                        result['title'] = TITLE_PENDING % (tag, GERRIT_PROJECT)
-                        result['message'] = UNDER_REVIEW_MSG % (tag, commitid)
-                    else:
-                        # The tag is on wrong branch
-                        result['title'] =  TITLE_FAILED % (tag, GERRIT_PROJECT)
-                        result['message'] = WRONG_VERSION_MSG % (tag, commitid, branch, branch)
-                else:
-                    # Cannot find the tagged commit in git tree or gerrit open change 
-                    print '\nCan not find this commit in gerrit open change, exit now'
-                    result['title'] = TITLE_FAILED % (tag, GERRIT_PROJECT)
-                    result['message'] = WRONG_COMMIT_MSG % (tag, commitid)
-        else:
-            # The time format in tag name is incorrect 
-            print '\nThe time format in tag name is incorrect, exit now'
-            result['title'] = TITLE_FAILED % (tag, GERRIT_PROJECT)
-            result['message'] = WRONG_DATE_MSG % (tag, date) 
+                # cannot find tagged commit in git tree or gerrit open change
+                message.append(WRONG_COMMIT_MSG % event['patchset_revision'])
     else:
-        print 'tag %s don\'t match the name format, exit now' % tag
-        result['title'] = TITLE_FAILED % (tag, GERRIT_PROJECT)
-        result['message'] = UNKNOWN_FORMAT_MSG % tag
+        # wrong tag format
+        message.append(UNKNOWN_FORMAT_MSG)
 
+    # check whether tag is an annotated tag
     tagger = git.get_tag(tag)
     if not tagger.has_key('author') or not tagger.has_key('email'):
-        if not result.has_key('title'):
-            result['title'] = TITLE_FAILED % (tag, GERRIT_PROJECT)
-        if result.has_key('message'):
-            result['message'] += '\n\nTag %s should be annotated tag.' % tag
-        else:
-            result['message'] = NOT_ANNOTATED_MSG % tag
-
-    return result
+        message.append(NOT_ANNOTATED_MSG)
+
+    # post comment to gerrit and send email if check failed
+    if message:
+        print message
+        msg = 'The tag %s is pushed, but this submission failed because of following reason(s):\n\n' % tag + \
+              '\n'.join(message)
+        if len(message) != 1 or message[0] != UNDER_REVIEW_MSG % event['patchset_revision']:
+            msg += '\n\n' + SUGGESTION
+        mygerrit.review(commit = event['patchset_revision'], message = msg)
+        send_mail(TITLE_FAILED % (tag, event['project']), msg, tagger)
+        return False
+
+    return True
+
+def is_tag_deleted(oldrev, newrev):
+    """check whehter tag is deleted"""
+
+    # 0000*0 is a special git hash code in gerrit for deleted git object
+    if oldrev != newrev and newrev == '0000000000000000000000000000000000000000':
+        return True
+    else:
+        return False
 
-def check_changes(obspkg, name, mygerrit, tag, tagger):
+def check_changes(obs_pkg, name, tag, tagger, event):
     """check whether this submission include modification for changes file"""
     changelog = '%s.changes' % name
-    if not os.path.isfile(os.path.join(obspkg.get_workdir(), '%s.changes' % name)):
-        chg = utils.find_changelog(obspkg.get_workdir())
+    if not os.path.isfile(os.path.join(obs_pkg.get_workdir(), '%s.changes' % name)):
+        chg = utils.find_changelog(obs_pkg.get_workdir())
         if chg:
             changelog = chg
 
     msg = ''
-    st = obspkg.status(changelog)
-    if st in ['?', '!', 'D']:
+    status = obs_pkg.status(changelog)
+    if status in ['?', '!', 'D']:
         # can not find changelog file under packaging directory
-        title = '[Warning] no changelog file found in submission: [%s] of %s' % (tag, GERRIT_PROJECT)
-        msg = '[Error] The "%s" branch of "%s" project does NOT contain change file under packaging directory! Please create "packaging/%s" and document the bug fix and/or features in this changelog file before your submission.' % (GERRIT_BRANCH, GERRIT_PROJECT, changelog)
-    elif st == ' ':
+        title = '[Warning] no changelog file found in submission: [%s] of %s' % (tag, event['project'])
+        msg = '[Error] The "%s" branch of "%s" project does NOT contain change file under packaging directory! Please create "packaging/%s" and document the bug fix and/or features in this changelog file before your submission.' % (event['branch'], event['project'], changelog)
+    elif status == ' ':
         # this submission didn't modify changelog file
-        title = '[Warning] no new changelog entry in submission: [%s] of %s' % (tag, GERRIT_PROJECT)
+        title = '[Warning] no new changelog entry in submission: [%s] of %s' % (tag, event['project'])
         msg = '[Error] Compare to last submission, this one (tag %s) does not contain any new entry for packaging/%s! Please add a new entry in change log to document the bug fix and/or feature before your submission. You can use "gbs changelog" to generate new entry, for details please refer to: https://source.tizen.org/documentation/reference/git-build-system/usage/gbs-changelog' % (tag, changelog)
-    elif st in ['M', 'A']:
+    elif status in ['M', 'A']:
         print 'This submission has updated changes file.'
 
-    print 'changes file status:', changelog, st, msg
+    print 'changes file status:', changelog, status, msg
     if msg:
-        feedback(msg, tag, tagger, mygerrit)
+        send_mail(title, msg, tagger)
         # current still follow origin process if no changelog update
-        #end('failure')
+        # return False
+
+    return True
+
+def find_specfile(prj_dir, packaging_dir, tag, event, tagger, pkg_name = None):
+    """search specfile under packaging directory"""
+
+    msg = ''
+
+    if pkg_name:
+        spec = '%s/%s/%s.spec' % (prj_dir, packaging_dir, pkg_name)
+        if not os.path.isfile(spec):
+            msg = "The tag %s pushed, but backend service can not find %s under packaging directory, which is caused by mistake OBS_PACKAGE parameter in scm/git-obs-mapping project. Please correct it or contact system administrator for more details." % (tag, os.path.basename(spec))
+    else:
+        specs = utils.find_spec('%s/%s' % (prj_dir, packaging_dir))
+        if not specs:
+            # no spec exist under packaging, use default name
+            msg = "The tag %s pushed, but packaging directory doesn't contain any spec file. Please create one and re-submit it." % tag
+        elif len(specs) == 1:
+            # only one spec exist under packaging
+            spec = specs[0]
+        else:
+            # multiple specs exist under packaging, use default name
+            spec = '%s/%s/%s.spec' % (prj_dir, packaging_dir, os.path.basename(event['project']))
+            if not os.path.isfile(spec):
+                msg = "The tag %s pushed, but packaging directory contains multiply spec files, backend service can not decide which spec file to use. Please use OBS_PACKAGE parameter in scm/git-obs-mapping project to specify the target spec file or contact system administrator for more details." % tag
+
+    if msg:
+        print msg
+        send_mail(TITLE_FAILED % (tag, event['project']), msg, tagger)
+        return None
+    else:
+        print('specfile %s' % spec)
+        return spec
+
+def parse_specfile(specfile, tmp_dir, prj_dir, packaging_dir, tag, event, tagger):
+    """parse specfile and use "gbs export" to generate tarball"""
+
+    spec = None
+    tarball_dir = None
+
+    try:
+        # use gbp to parse specfile
+        spec = gbp.rpm.parse_spec(specfile)
+        # use gbs export to generate tarball
+        outdir = tempfile.mkdtemp(prefix=tmp_dir+'/')
+        with utils.Workdir(prj_dir):
+            runner.show('gbs export --spec %s --packaging-dir %s -o %s' % (os.path.basename(specfile), packaging_dir, outdir))
+    except Exception, exc:
+        print('gbp parse spec failed. %s' % exc)
+        msg = "The tag %s pushed, but backend service failed to parse %s. Please make sure (gbs export) can work in this project." % (tag, os.path.basename(specfile))
+        send_mail(TITLE_FAILED % (tag, event['project']), msg, tagger)
+        return None, None
+
+    tarball_dir = os.path.join(outdir, os.listdir(outdir)[0])
+
+    return spec, tarball_dir
 
 def main():
-    # global variable
-    global GERRIT_PATCHSET_REVISION
+    """script entry point"""
+
+    # prepare related global variables
+    workspace = os.getenv('WORKSPACE')
+    gitcache = os.getenv('GIT_CACHE_DIR')
+    mapping_prj = os.getenv('MAPPING_PRJ')
+    apiurl = os.getenv('OBS_API_URL')
+    apiuser = os.getenv('OBS_API_USERNAME')
+    apipasswd = os.getenv('OBS_API_PASSWD')
+
+    event = get_gerrit_event()
+    # prepare separate temp directory for each build
+    tmpdir = tempfile.mkdtemp(prefix=workspace+'/')
+    prjdir = os.path.join(tmpdir, event['project'])
+
     print '---[JOB STARTED]----------------------------------------'
     # check whether tag name is start with 'submit/'
-    if GERRIT_EVENT_TYPE == "REF_UPDATED":
-        if not GERRIT_REFNAME.startswith('refs/tags/submit/'):
-            print '\nREFNAME "%s" isn\'t start with refs/tags/submit, exit now' % GERRIT_REFNAME
-            end('success')
-        elif is_ref_deleted(GERRIT_OLDREV, GERRIT_NEWREV):
-            print '\nREFNAME "%s" is deleted, exit now' % GERRIT_REFNAME
-            end('success')
+    if event['event_type'] == "ref-updated":
+        if not event['refname'].startswith('refs/tags/submit/'):
+            print '\nREFNAME "%s" isn\'t start with refs/tags/submit, exit now' % event['refname']
+            return 0
+        elif is_tag_deleted(event['oldrev'], event['newrev']):
+            print '\nREFNAME "%s" is deleted, exit now' % event['refname']
+            return 0
 
     # check whether git-obs-mapping.xml exist in local
-    if not os.path.isfile('%s/%s/git-obs-mapping.xml' % (GIT_CACHE_DIR, MAPPING_PRJ)):
-        print('Update %s/git-obs-mapping.xml to local.' % MAPPING_PRJ)
-        if not clone_gitproject(MAPPING_PRJ, os.path.join(GIT_CACHE_DIR, MAPPING_PRJ)):
-            end('retry')
+    if not os.path.isfile('%s/%s/git-obs-mapping.xml' % (gitcache, mapping_prj)):
+        print('Update %s/git-obs-mapping.xml to local.' % mapping_prj)
+        if not clone_gitproject(mapping_prj, os.path.join(gitcache, mapping_prj)):
+            return 1
 
     # quit directly if project do not map to any OBS project
-    mymapping = mapping.Mapping('%s/%s/git-obs-mapping.xml' % (GIT_CACHE_DIR, MAPPING_PRJ))
-    if not mymapping.get_submit_mapping(GERRIT_PROJECT):
+    mymapping = mapping.Mapping('%s/%s/git-obs-mapping.xml' % (gitcache, mapping_prj))
+    if not mymapping.get_submit_mapping(event['project']):
         print '\nThis project do not map to any OBS project, exit now'
-        end('success')
+        return 0
 
     # clone gerrit project to local dir
-    if not clone_gitproject(GERRIT_PROJECT, prjdir):
-        end('retry')
+    if not clone_gitproject(event['project'], prjdir):
+        return 1
 
     mygit = Git(prjdir)
-    mygerrit = gerrit.Gerrit(GERRIT_HOSTNAME, GERRIT_USERNAME, GERRIT_SSHPORT)
+    mygerrit = gerrit.Gerrit(event['hostname'], event['username'], event['sshport'])
 
-    if GERRIT_EVENT_TYPE == "REF_UPDATED":
-        tag = GERRIT_REFNAME[len('refs/tags/'):]
-    else:
-        # Only when there is tag submit/*, it's for submit
-        if GERRIT_BRANCH == 'master':
-            branch = 'trunk'
-        else:
-            branch = GERRIT_BRANCH
-        tag = mygit.describe('--exact-match', '--match', 'submit/%s/*' %
-                branch, GERRIT_PATCHSET_REVISION)
-        if tag:
-            print 'submit tag : %s, on branch %s'  % (tag, GERRIT_BRANCH)
-        else:
-            print '\nThis change don\'t contain submit/*/* tag, exit now'
-            end('success')
+    tag = find_submit_tag(event, mygit)
+    if not tag:
+        print '\nThis commit don\'t contain submit/*/* tag, exit now'
+        return 0
 
-    # check tag format
-    tagcheck = check_tag_format(tag, mygit, mygerrit)
+    # check whether tag meet format
+    if not check_tag_format(mygit, mygerrit, event, tag):
+        return 0
 
     tagger = mygit.get_tag(tag)
-    if not GERRIT_PATCHSET_REVISION:
-        GERRIT_PATCHSET_REVISION = mygit.rev_parse(tag)
-    commitinfo = mygit.get_commit_info(GERRIT_PATCHSET_REVISION)
-
-    # parse git-obs-mapping to get OBS target project, exit if not map to any project
-    obstargets = mymapping.get_submit_mapping(GERRIT_PROJECT, GERRIT_BRANCH)
-    print 'git-obs-mapping:', GERRIT_PROJECT, GERRIT_BRANCH, obstargets
-    if not tagcheck and not obstargets:
-        tagcheck = {}
-        tagcheck['title'] = TITLE_FAILED % (tag, GERRIT_PROJECT)
-        tagcheck['message'] = NO_MAPPING_MSG % (tag, GERRIT_BRANCH)
-
-    # post comment and send email if tag format check failed
-    if tagcheck:
-        print tagcheck
-        mygerrit.review(commit = GERRIT_PATCHSET_REVISION, message = tagcheck['message'])
-        if tagger.has_key('author') and tagger.has_key('email'):
-            tagcheckmsg = 'Hi, %s,\n\n' % tagger['author'] + tagcheck['message'] + '\n\n----------------------------------------------------------------\nAutomatically generated by backend service.\nPlease DO NOT Reply!'
-            prepare_mail("%s.mail.env" % random.random(), tagcheck['title'], tagcheckmsg, NOREPLY_EMAIL_SENDER, tagger['email'])
-        end('success')
+    commitinfo = mygit.get_commit_info(event['patchset_revision'])
+
+    # parse git-obs-mapping to get OBS target project
+    obstargets = mymapping.get_submit_mapping(event['project'], event['branch'])
+    print 'git-obs-mapping:', event['project'], event['branch'], obstargets
 
     packagingdir = utils.parse_link('%s/%s' % (prjdir, 'packaging'))
     print('packaging dir is %s/%s' % (prjdir, packagingdir))
 
-    msg = 'Submitter: %s <%s>\nComments: %s\nGit project: %s\nTag: %s\nCommit: %s %s' % (tagger['author'], tagger['email'], tagger['message'], GERRIT_PROJECT, tag, commitinfo['id'], commitinfo['subject'])
-
-    # to support pristine-tar, checkout upstream and pristine-tar branch to local
+    # to support pristine-tar, checkout upstream and pristine-tar branch
     if mygit.has_branch('origin/upstream', remote=True):
         mygit.checkout('upstream')
     if mygit.has_branch('origin/pristine-tar', remote=True):
@@ -276,6 +311,7 @@ def main():
     # checkout submit tag
     mygit.checkout(tag)
 
+    # generate tarball and submit to obs
     for target in obstargets:
         mygit.clean('-fd')
         (obs_dst_prj, obs_stg_prj, obs_pkg) = target
@@ -285,63 +321,26 @@ def main():
         if not obs_stg_prj:
             obs_stg_prj = obs_dst_prj
 
-        if obs_pkg:
-            specfile = '%s/%s/%s.spec' % (prjdir, packagingdir, obs_pkg)
-            if not os.path.isfile(specfile):
-                msg = "The tag %s pushed, but backend service can not find %s under packaging directory, which is caused by mistake OBS_PACKAGE parameter in scm/git-obs-mapping project. Please correct it or contact system administrator for more details." % (tag, os.path.basename(specfile))
-                feedback(msg, tag, tagger, mygerrit)
-                end('failure')
-        else:
-            specs = utils.find_spec('%s/%s' % (prjdir, packagingdir))
-            if not specs:
-                # no spec exist under packaging, use default name
-                msg = "The tag %s pushed, but packaging directory doesn't contain any spec file. Please create one and re-submit it." % tag
-                feedback(msg, tag, tagger, mygerrit)
-                end('failure')
-            elif len(specs) == 1:
-                # only one spec exist under packaging
-                specfile = specs[0]
-            else:
-                # multiple specs exist under packaging, use default name
-                specfile = '%s/%s/%s.spec' % (prjdir, packagingdir, prj)
-                if not os.path.isfile(specfile):
-                    msg = "The tag %s pushed, but packaging directory contains multiply spec files, backend service can not decide which spec file to use. Please use OBS_PACKAGE parameter in scm/git-obs-mapping project to specify the target spec file or contact system administrator for more details." % tag
-                    feedback(msg, tag, tagger, mygerrit)
-                    end('failure')
-
-        print('specfile %s' % specfile)
-
-        try:
-            # use gbp to parse specfile
-            spec = gbp.rpm.parse_spec(specfile)
-            # use gbs export to generate tarball
-            outdir = tempfile.mkdtemp(prefix=tmpdir+'/')
-            with utils.Workdir(prjdir):
-                runner.show('gbs export --spec %s --packaging-dir %s -o %s' % (os.path.basename(specfile), packagingdir, outdir))
-        except Exception, exc:
-            print('gbp parse spec failed. %s' % exc)
-            msg = "The tag %s pushed, but backend service faile to parse %s. Please make sure (gbs export) can work in this project." % (tag, os.path.basename(specfile))
-            feedback(msg, tag, tagger, mygerrit)
-            end('failure')
-
-        tarballdir = os.path.join(outdir, os.listdir(outdir)[0])
+        # search specfile under packaging directory
+        specfile = find_specfile(prjdir, packagingdir, tag, event, tagger, obs_pkg)
+        if not specfile:
+            return 0
+
+        # parse specfile and use "gbs export" to generate tarball
+        spec, tarballdir = parse_specfile(specfile, tmpdir, prjdir, packagingdir, tag, event, tagger)
+        if not spec or not tarballdir:
+            return 0
 
         retry_count = 3
         while retry_count > 0:
             try:
                 if obs_stg_prj != obs_dst_prj:
-                    tmppkg = obspkg.ObsPackage(tmpdir, obs_stg_prj, 'tmp',
-                                               apiurl = OBS_API_URL,
-                                               apiuser = OBS_API_USERNAME,
-                                               apipasswd = OBS_API_PASSWD)
+                    tmppkg = obspkg.ObsPackage(tmpdir, obs_stg_prj, 'tmp', apiurl, apiuser, apipasswd)
                     if tmppkg.is_new_pkg():
                         tmppkg.commit("Leave an empty package in this project to prevent OBS delete it automatically when all request from here are accepted.")
 
                 print '\nCheckout %s/%s to local' % (obs_stg_prj, spec.name)
-                localpkg = obspkg.ObsPackage(tmpdir, obs_stg_prj, spec.name,
-                                             apiurl = OBS_API_URL,
-                                             apiuser = OBS_API_USERNAME,
-                                             apipasswd = OBS_API_PASSWD)
+                localpkg = obspkg.ObsPackage(tmpdir, obs_stg_prj, spec.name, apiurl, apiuser, apipasswd)
                 oscworkdir = localpkg.get_workdir()
                 localpkg.remove_all()
                 for myfile in os.listdir(tarballdir):
@@ -350,17 +349,15 @@ def main():
                 localpkg.update_local()
 
                 # check whether this submission inclued modification for changes file
-                check_changes(localpkg, spec.name, mygerrit, tag, tagger)
+                if not check_changes(localpkg, spec.name, tag, tagger, event):
+                    return 1
 
                 # submit local pkg to obs and create sr
                 print '\nSubmit local pkg to obs...'
-                localpkg.commit(msg)
+                commit_msg = 'Submitter: %s <%s>\nComments: %s\nGit project: %s\nTag: %s\nCommit: %s %s' % (tagger['author'], tagger['email'], tagger['message'], event['project'], tag, commitinfo['id'], commitinfo['subject'])
+                localpkg.commit(commit_msg)
                 if obs_stg_prj != obs_dst_prj:
-                    #for req in localpkg.query_req(obs_dst_prj):
-                    #    msg += '\n\n%s' % req.description
-                    #    print 'supersede previous SR %s' % req.reqid
-                    print '\nsr msg:\n%s' % msg
-                    newreq = localpkg.submit_req(obs_dst_prj, msg=msg)
+                    newreq = localpkg.submit_req(obs_dst_prj, msg=commit_msg)
                     print 'New request %s is created' % newreq
                 break
             except Exception, exc:
@@ -370,30 +367,23 @@ def main():
                 retry_count -= 1
 
         if not retry_count:
-            end('retry')
+            return 1
 
         # post sr info back to gerrit
+        comment = '- Submitter: %s <%s>\n- Comments: %s\n- Git project: %s\n- Tag: %s\n- Commit: %s %s' % (tagger['author'], tagger['email'], tagger['message'], event['project'], tag, commitinfo['id'], commitinfo['subject'])
         if obs_stg_prj != obs_dst_prj:
-            requrl = ' %s/request/show/%s' % (OBS_URL, newreq)
-            comment = 'A SR (Submit Request) has been triggered to submit the commit to OBS %s project.\n- Submitter: %s <%s>\n- Comments: %s\n- Git project: %s\n- Tag: %s\n- Commit: %s %s\n- Request URL:%s' % (obs_dst_prj, tagger['author'], tagger['email'], tagger['message'], GERRIT_PROJECT, tag, commitinfo['id'], commitinfo['subject'], requrl)
+            # submit to :build project and create a SR
+            requrl = ' %s/request/show/%s' % (os.getenv('OBS_URL'), newreq)
+            comment = 'A SR (Submit Request) has been triggered to submit the commit to OBS %s project.\n' % obs_dst_prj + \
+                      comment + '\n' + \
+                      '- Request URL:%s' % requrl
         else:
-            comment = 'This commit has been submitted to OBS %s project.\n- Submitter: %s <%s>\n- Comments: %s\n- Git project: %s\n- Tag: %s\n- Commit: %s %s' % (obs_dst_prj, tagger['author'], tagger['email'], tagger['message'], GERRIT_PROJECT, tag, commitinfo['id'], commitinfo['subject'])
-        mygerrit.review(commit = GERRIT_PATCHSET_REVISION, message = comment)
+            # submit to final target project directly
+            comment = 'This commit has been submitted to OBS %s project.\n' % obs_dst_prj + comment
+        mygerrit.review(commit = event['patchset_revision'], message = comment)
 
-        '''
-        comment = 'Hi, %s,\n\n' % tagger['author'] + comment + '\n\n----------------------------------------------------------------\nAutomatically generated by backend service.\nPlease DO NOT Reply!' 
-        prepare_mail("%s.mail.env" % random.random(), '[Submit Request]: changes to %s/%s' % (obs_dst_prj, spec.name), comment, FROM_EMAIL, tagger['email'])
-        '''
-    end('success')
+    return 0
 
 if __name__ == '__main__':
-    # prepare separate temp directory for each build
-    tmpdir = tempfile.mkdtemp(prefix=WORKSPACE+'/')
-    prjdir = os.path.join(tmpdir, GERRIT_PROJECT)
-    prjpath, prj = os.path.split(GERRIT_PROJECT)
 
-    try:
-        main()
-    except Exception, exc:
-        print exc
-        end('failure')
+    sys.exit(main())