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)
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')
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)