Exemplo n.º 1
0
def process_comment_event(event):
    if event.note[
            'noteable_type'] != 'MergeRequest' or event.author_id == cfg.gl_bot_uid:
        return

    mr = wine_gl.mergerequests.get(event.note['noteable_id'])
    note = mr.notes.get(event.target_id)
    print(note)

    # Find discussion object
    discussion_id = None
    if event.target_type == 'Note':
        # Not part of a discussion, just find the root email for the MR
        discussion_id = 0
    if event.target_type == 'DiscussionNote':
        # Find the discussion, by finding which discussion contains the note
        for discussion in mr.discussions.list(all=True):
            for discussion_note in discussion.attributes['notes']:
                print(discussion_note)
                if discussion_note['id'] == note.id:
                    discussion_id = discussion.id
                    break
            if discussion_id is not None: break
    if event.target_type == 'DiffNote':
        discussion_id = note.position['start_sha']
    assert discussion_id is not None

    discussion_entry = db_helper.Discussion(mr.id, discussion_id)
    mail_thread = db_helper.lookup_mail_thread(discussion_entry)
    mr_thread = db_helper.lookup_mail_thread(db_helper.Discussion(mr.id, 0))
    child = mail_thread is not None

    comment_body = note.body
    if not child and event.target_type == 'DiffNote':
        comment_body = '> `TODO: put diff information here`\n\n' + comment_body

    sent_msg_id = mail_helper.send_mail(
        'Gitlab Merge-Request Comment',
        comment_body,
        in_reply_to=mail_thread if child else mr_thread)
    if child:
        db_helper.add_child(mail_thread, sent_msg_id)
    else:
        db_helper.link_discussion_to_mail(discussion_entry, sent_msg_id)
Exemplo n.º 2
0
def process_mr_event(event, mr):
    print(mr.author)
    if (
            event.action_name == 'opened' or event.action_name == 'pushed to'
    ) and not mr.author['id'] == cfg.gl_bot_uid and not mr.work_in_progress:
        # Forward merge request as patchset to mailing list when it is created or updated
        print('updating ML')
        # Lookup the merge request to get info about how to send it to the ML
        primary_discussion = db_helper.Discussion(mr.id, 0)
        msg_id = db_helper.lookup_mail_thread(primary_discussion)
        version = None
        if msg_id is None:
            # This means we haven't already sent a version of this MR to the mailing list, so we send the header and setup the row
            # TODO: if the MR only has one patch, batch up the MR description w/ the commit description and use that as the header/prologue
            msg_id = mail_helper.send_mail(
                mr.title,
                mr.description + '\n\nMerge-Request Link: ' + mr.web_url)
            db_helper.link_discussion_to_mail(primary_discussion, msg_id)
            db_helper.make_version_entry(mr.id)
            version = 1
        else:
            version = db_helper.get_mr_version(mr.id) + 1
            db_helper.set_mr_version(mr.id, version)
        patch_prefix = 'PATCH v' + str(version) if version != 1 else 'PATCH'

        # If this is an opening event, and the MR has been updated since, we have problems
        top_hash = event.push_data[
            'commit_to'] if event.action_name == 'pushed to' else find_mr_initial_hash(
                mr)

        # Add a branch referencing the top commit to ensure we can access this version
        source_project = gl.projects.get(mr.source_project_id)
        source_project.branches.create({
            'branch': 'temporary_scraper_branch',
            'ref': top_hash
        })
        # Add the project as a remote
        wine_git.remote('add', 'mr_source', source_project.http_url_to_repo)
        wine_git.fetch('mr_source')

        # Format patches for submission
        wine_git.format_patch('origin..' + top_hash,
                              subject_prefix=patch_prefix)

        # Remove the remote
        wine_git.remote('remove', 'mr_source')

        # Remove the branch
        source_project.branches.delete('temporary_scraper_branch')

        #send them
        #TODO: if a patch was deleted, we won't end up sending anything, maybe send a notification about the deletions instead?
        for file_path in sorted(cfg.local_wine_git_path.iterdir()):
            if file_path.name.endswith('.patch'):
                # Create the discussion and the thread, then link them

                with file_path.open() as patch_file:
                    contents = patch_file.read()

                search = re.search(r'^From (?P<commithash>\w*)', contents)
                assert search is not None
                commit_hash = search.group('commithash')
                assert commit_hash is not None

                if db_helper.remember_commit_hash(mr, commit_hash):
                    # We have already sent this patch, skip it
                    continue

                patch_discussion = mr.discussions.create(
                    {'body': 'Discussion on commit ' + commit_hash})

                search = re.search(r'(?m)^Subject: (?P<subject>.*)$', contents)
                assert search is not None
                patch_subject = search.group('subject')
                assert patch_subject is not None
                patch_msg_id = mail_helper.send_mail(patch_subject,
                                                     contents.split('\n\n',
                                                                    1)[1],
                                                     in_reply_to=msg_id)

                db_helper.link_discussion_to_mail(
                    db_helper.Discussion(mr.id, patch_discussion.id),
                    patch_msg_id)
        # Clean Up
        wine_git.reset('origin/master', hard=True)
        wine_git.clean(force=True)
        return

    if mr.author['id'] == cfg.gl_bot_uid:
        # Turn MR events into emails sent back to the submitter
        print('TODO')
Exemplo n.º 3
0
def create_or_update_merge_request(mr, title, author, description, patches,
                                   prologue_msg_id):
    # create the local git branch
    branch_name = None
    if mr is None:
        branch_name = 'ml-patchset-{0}'.format(time.time())
        LOCAL_REPO_GIT.checkout('HEAD', b=branch_name)
    else:
        branch_name = mr.source_branch
        LOCAL_REPO_GIT.checkout(branch_name)
        LOCAL_REPO_GIT.reset('master', hard=True)

    # apply the patches
    try:
        for patch in patches:
            LOCAL_REPO_GIT.am(str(patch.path))
    except:
        print('Failed to apply patches, discarding patchset')
        # TODO: make more robust, and send email back if it didn't apply
        if mr is not None:
            LOCAL_REPO_GIT.reset('origin/' + branch_name, hard=True)
        LOCAL_REPO_GIT.checkout('master')
        if mr is None:
            LOCAL_REPO_GIT.branch(D=branch_name)
        return
    finally:
        for patch in patches:
            patch.path.unlink()

    LOCAL_REPO_GIT.checkout('master')

    # push work to origin
    LOCAL_REPO_GIT.push('origin', branch_name, force=True)

    # create merge request
    if mr is None:
        mr = FORK_REPO.mergerequests.create({
            'source_branch':
            branch_name,
            'target_project_id':
            cfg.MAIN_REPO_ID,
            'target_branch':
            'master',
            'title':
            title
            if title is not None else 'Multi-Patch Patchset from Mailing List',
            'description':
            description
        })
        if not cfg.BIDIRECTIONAL_COMM:
            admin_mr = ADMIN_PROJECT_VIEW.mergerequests.get(mr.id)
            admin_mr.discussion_locked = True
            admin_mr.save()

        # send email to mailing list as a place to put MR comments
        if prologue_msg_id is None:
            if len(patches) == 1:
                db_helper.link_discussion_to_mail(
                    db_helper.Discussion(mr.id, 0), patches[0].msgid)
                return
            # send meta email if prologue wasn't sent
            mail_helper.send_mail(
                'Gitlab discussion thread for recent patchset by' + author,
                'Merge-Request Link: ' + mr.web_url)
        else:
            db_helper.link_discussion_to_mail(db_helper.Discussion(mr.id, 0),
                                              prologue_msg_id)
    elif prologue_msg_id and len(patches) != 1:
        extra_discussion = mr.discussions.create(
            {'body': 'Discussion on updated commits'})
        db_helper.link_discussion_to_mail(
            db_helper.Discussion(mr.id, extra_discussion.id), prologue_msg_id)

    # create a discussion for each patch
    for patch in patches:
        patch_discussion = mr.discussions.create(
            {'body': 'Discussion for {0}'.format(patch.subject)})
        # link mail thread to discussion
        db_helper.link_discussion_to_mail(
            db_helper.Discussion(mr.id, patch_discussion.id), patch.msgid)