def __email_ref_update(self): """Send the email describing to the reference update. This email can be seen as a "cover email", or a quick summary of the update that was performed. REMARKS The hooks may decide that such an email may not be necessary, and thus send nothing. See self.get_update_email_contents for more details. """ update_email_contents = self.get_update_email_contents() if update_email_contents is not None: (email_to, subject, body) = update_email_contents update_email = Email(self.email_info, email_to, subject, body, None, self.ref_name, self.old_rev, self.new_rev, send_to_filer=self.send_cover_email_to_filer) update_email.enqueue()
def email_commit(self, commit): """Send an email describing the given commit. PARAMETERS commit: A CommitInfo object. """ if self.ref_namespace in ('refs/heads', 'refs/tags'): if self.short_ref_name == 'master': branch = '' else: branch = '/%s' % self.short_ref_name else: # Unusual namespace for our reference. Use the reference # name in full to label the branch name. branch = '(%s)' % self.ref_name subject = '[%(repo)s%(branch)s] %(subject)s' % { 'repo': self.email_info.project_name, 'branch': branch, 'subject': commit.subject[:SUBJECT_MAX_SUBJECT_CHARS], } # Generate the body of the email in two pieces: # 1. The commit description without the patch; # 2. The diff stat and patch. # This allows us to insert our little "Diff:" marker that # bugtool detects when parsing the email for filing (this # part is now performed by the Email class). The purpose # is to prevent bugtool from searching for TNs in the patch # itself. # # For the diff, there is one subtlelty: # Git commands calls strip on the output, which is usually # a good thing, but not in the case of the diff output. # Prevent this from happening by putting an artificial # character at the start of the format string, and then # by stripping it from the output. body = git.log(commit.rev, max_count="1") + '\n' if git_config('hooks.commit-url') is not None: url_info = {'rev': commit.rev, 'ref_name': self.ref_name} body = (git_config('hooks.commit-url') % url_info + '\n\n' + body) diff = git.show(commit.rev, p=True, M=True, stat=True, pretty="format:|")[1:] filer_cmd = git_config('hooks.file-commit-cmd') if filer_cmd is not None: filer_cmd = shlex.split(filer_cmd) email = Email(self.email_info, commit.email_to, subject, body, commit.author, self.ref_name, commit.base_rev_for_display(), commit.rev, diff, filer_cmd=filer_cmd) email.enqueue()
def email_commit(self, commit): """See AbstractUpdate.email_commit.""" notes = GitNotes(commit.rev) # Get commit info for the annotated commit annotated_commit = commit_info_list("-1", notes.annotated_rev)[0] # Get a description of the annotated commit (a la "git show"), # except that we do not want the diff. # # Also, we have to handle the notes manually, as the commands # get the notes from the HEAD of the notes/commits branch, # whereas what we needs is the contents at the commit.rev. # This makes a difference when a single push updates the notes # of the same commit multiple times. annotated_rev_log = git.log(annotated_commit.rev, no_notes=True, max_count="1") notes_contents = (None if notes.contents is None else indent( notes.contents, ' ' * 4)) # Determine subject tag based on ref name: # * remove "refs/notes" prefix # * remove entire tag if remaining component is "commits" # (case of the default refs/notes/commits ref) notes_ref = self.ref_name.split('/', 2)[2] if notes_ref == "commits": subject_tag = "" else: subject_tag = "(%s)" % notes_ref subject = '[notes%s][%s] %s' % (subject_tag, self.email_info.project_name, annotated_commit.subject) body_template = (DELETED_NOTES_COMMIT_EMAIL_BODY_TEMPLATE if notes_contents is None else UPDATED_NOTES_COMMIT_EMAIL_BODY_TEMPLATE) body = body_template % { 'annotated_rev_log': annotated_rev_log, 'notes_contents': notes_contents, } # Git commands calls strip on the output, which is usually # a good thing, but not in the case of the diff output. # Prevent this from happening by putting an artificial # character at the start of the format string, and then # by stripping it from the output. diff = git.show(commit.rev, pretty="format:|", p=True)[1:] email_bcc = git_config('hooks.filer-email') email = Email(self.email_info, annotated_commit.email_to(self.ref_name), email_bcc, subject, body, commit.author, self.ref_name, commit.base_rev_for_display(), commit.rev, diff) email.enqueue()
def email_commit(self, commit): """See AbstractUpdate.email_commit.""" notes = GitNotes(commit.rev) # Create a partial CommitInfo object for the commit that # our note annotates. We create a partial one in order # to avoid computing some info we do not need... annotated_commit = CommitInfo(notes.annotated_rev, None, None, None) # Get a description of the annotated commit (a la "git show"), # except that we do not want the diff. # # Also, we have to handle the notes manually, as the commands # get the notes from the HEAD of the notes/commits branch, # whereas what we needs is the contents at the commit.rev. # This makes a difference when a single push updates the notes # of the same commit multiple times. annotated_rev_info = git.log(annotated_commit.rev, no_notes=True, max_count="1") notes_contents = (None if notes.contents is None else indent( notes.contents, ' ' * 4)) subject = '[%s] notes update for %s' % (self.email_info.project_name, notes.annotated_rev) body_template = (DELETED_NOTES_COMMIT_EMAIL_BODY_TEMPLATE if notes_contents is None else UPDATED_NOTES_COMMIT_EMAIL_BODY_TEMPLATE) body = body_template % { 'annotated_rev_info': annotated_rev_info, 'notes_contents': notes_contents, } # Git commands calls strip on the output, which is usually # a good thing, but not in the case of the diff output. # Prevent this from happening by putting an artificial # character at the start of the format string, and then # by stripping it from the output. diff = git.show(commit.rev, pretty="format:|", p=True)[1:] email = Email(self.email_info, annotated_commit.email_to, subject, body, commit.author, self.ref_name, commit.base_rev_for_display(), commit.rev, diff) email.enqueue()
def email_commit(self, commit): """See AbstractUpdate.email_commit.""" notes = GitNotes(commit.rev) # Create a partial CommitInfo object for the commit that # our note annotates. We create a partial one in order # to avoid computing some info we do not need... annotated_commit = CommitInfo(notes.annotated_rev, None, None, None) # Get a description of the annotated commit (a la "git show"), # except that we do not want the diff. # # Also, we have to handle the notes manually, as the commands # get the notes from the HEAD of the notes/commits branch, # whereas what we needs is the contents at the commit.rev. # This makes a difference when a single push updates the notes # of the same commit multiple times. annotated_rev_info = git.log(annotated_commit.rev, no_notes=True, max_count="1") notes_contents = (None if notes.contents is None else indent(notes.contents, ' ' * 4)) subject = '[%s] notes update for %s' % (self.email_info.project_name, notes.annotated_rev) body_template = ( DELETED_NOTES_COMMIT_EMAIL_BODY_TEMPLATE if notes_contents is None else UPDATED_NOTES_COMMIT_EMAIL_BODY_TEMPLATE) body = body_template % { 'annotated_rev_info': annotated_rev_info, 'notes_contents': notes_contents, } # Git commands calls strip on the output, which is usually # a good thing, but not in the case of the diff output. # Prevent this from happening by putting an artificial # character at the start of the format string, and then # by stripping it from the output. diff = git.show(commit.rev, pretty="format:|", p=True)[1:] email = Email(self.email_info, annotated_commit.email_to, subject, body, commit.author, self.ref_name, commit.base_rev_for_display(), commit.rev, diff) email.enqueue()
def email_commit(self, commit): """Send an email describing the given commit. PARAMETERS commit: A CommitInfo object. """ if self.ref_namespace in ('refs/heads', 'refs/tags'): if self.short_ref_name == 'master': branch = '' else: branch = '/%s' % self.short_ref_name else: # Unusual namespace for our reference. Use the reference # name in full to label the branch name. branch = '(%s)' % self.ref_name subject = '[%(repo)s%(branch)s] %(subject)s' % { 'repo': self.email_info.project_name, 'branch': branch, 'subject': commit.subject[:SUBJECT_MAX_SUBJECT_CHARS], } # Generate the body of the email in two pieces: # 1. The commit description without the patch; # 2. The diff stat and patch. # This allows us to insert our little "Diff:" marker that # bugtool detects when parsing the email for filing (this # part is now performed by the Email class). The purpose # is to prevent bugtool from searching for TNs in the patch # itself. # # For the diff, there is one subtlelty: # Git commands calls strip on the output, which is usually # a good thing, but not in the case of the diff output. # Prevent this from happening by putting an artificial # character at the start of the format string, and then # by stripping it from the output. body = git.log(commit.rev, max_count="1") + '\n' if git_config('hooks.commit-url') is not None: url_info = {'rev': commit.rev, 'ref_name': self.ref_name} body = (git_config('hooks.commit-url') % url_info + '\n\n' + body) if git_config('hooks.disable-email-diff'): diff = None else: diff = git.show(commit.rev, p=True, M=True, stat=True, pretty="format:|")[1:] filer_cmd = git_config('hooks.file-commit-cmd') if filer_cmd is not None: filer_cmd = shlex.split(filer_cmd) email_bcc = git_config('hooks.filer-email') email = Email(self.email_info, commit.email_to(self.ref_name), email_bcc, subject, body, commit.author, self.ref_name, commit.base_rev_for_display(), commit.rev, diff, filer_cmd=filer_cmd) email.enqueue()
def get_standard_commit_email(self, commit): """See AbstractUpdate.get_standard_commit_email.""" notes = GitNotes(commit.rev) # Get commit info for the annotated commit annotated_commit = commit_info_list("-1", notes.annotated_rev)[0] # Get a description of the annotated commit (a la "git show"), # except that we do not want the diff. # # Also, we have to handle the notes manually, as the commands # get the notes from the HEAD of the notes/commits branch, # whereas what we needs is the contents at the commit.rev. # This makes a difference when a single push updates the notes # of the same commit multiple times. annotated_rev_log = git.log(annotated_commit.rev, no_notes=True, max_count="1", _decode=True) notes_contents = (None if notes.contents is None else indent( notes.contents, " " * 4)) # Get the list of references the annotated commit is contained in. annotated_commit_ref_names = git.for_each_ref( contains=annotated_commit.rev, format="%(refname)", _decode=True, _split_lines=True, ) # Strip from that list all the references which are to be ignored # (typically, those are internal references). annotated_commit_ref_names = [ ref_name for ref_name in annotated_commit_ref_names if search_config_option_list("hooks.ignore-refs", ref_name) is None ] subject_prefix = commit_email_subject_prefix( project_name=self.email_info.project_name, ref_names=annotated_commit_ref_names, ) # Determine subject tag based on ref name: # * remove "refs/notes" prefix # * remove entire tag if remaining component is "commits" # (case of the default refs/notes/commits ref) notes_ref = self.ref_name.split("/", 2)[2] if notes_ref == "commits": subject_tag = "" else: subject_tag = "(%s)" % notes_ref subject = f"[notes{subject_tag}]{subject_prefix} {annotated_commit.subject}" body_template = (DELETED_NOTES_COMMIT_EMAIL_BODY_TEMPLATE if notes_contents is None else UPDATED_NOTES_COMMIT_EMAIL_BODY_TEMPLATE) body = body_template % { "annotated_rev_log": annotated_rev_log, "notes_contents": notes_contents, } # Git commands calls strip on the output, which is usually # a good thing, but not in the case of the diff output. # Prevent this from happening by putting an artificial # character at the start of the format string, and then # by stripping it from the output. diff = git.show(commit.rev, pretty="format:|", p=True, _decode=True)[1:] refs_containing_annotated_commit_section = ( REFS_CONTAINING_ANNOTATED_COMMIT_TEMPLATE.format( annotated_commit_references="\n".join([ f" {ref_name}" for ref_name in annotated_commit_ref_names ]))) email_bcc = git_config("hooks.filer-email") return Email( self.email_info, annotated_commit.email_to(self.ref_name), email_bcc, subject, body, commit.full_author_email, self.ref_name, commit.base_rev_for_display(), commit.rev, # Place the refs_containing_annotated_commit_section inside # the "Diff:" section to avoid having that section trigger # some unexpected filing. refs_containing_annotated_commit_section + diff, )
def get_standard_commit_email(self, commit): """Return an Email object for the given commit. Here, "standard" means that the Email returned corresponds to the Email the git-hooks sends by default, before any possible project-specific customization is applied. Before sending this email, users of this method are expected to apply those customizations as needed. PARAMETERS commit: A CommitInfo object. """ subject_prefix = commit_email_subject_prefix( self.email_info.project_name, self.ref_name, ) subject = f"{subject_prefix} {commit.subject[:SUBJECT_MAX_SUBJECT_CHARS]}" # Generate the body of the email in two pieces: # 1. The commit description without the patch; # 2. The diff stat and patch. # This allows us to insert our little "Diff:" marker that # bugtool detects when parsing the email for filing (this # part is now performed by the Email class). The purpose # is to prevent bugtool from searching for TNs in the patch # itself. body = git.log(commit.rev, max_count="1", _decode=True) + "\n" if git_config("hooks.commit-url") is not None: url_info = {"rev": commit.rev, "ref_name": self.ref_name} body = git_config("hooks.commit-url") % url_info + "\n\n" + body if git_config("hooks.disable-email-diff"): diff = None else: diff = git.show(commit.rev, p=True, M=True, stat=True, pretty="format:") # Decode the diff line-by-line: # # It seems conceivable that the diff may cover multiple files, # and that the files may have different encodings, so we cannot # assume that the entire output follows the same encoding. diff = safe_decode_by_line(diff) # Add a small "---" separator line at the beginning of # the diff section we just computed. This mimicks what # "git show" would do if we hadn't provided an empty # "format:" string to the "--pretty" command-line option. diff = "---\n" + diff filer_cmd = git_config("hooks.file-commit-cmd") if filer_cmd is not None: filer_cmd = shlex.split(filer_cmd) email_bcc = git_config("hooks.filer-email") return Email( self.email_info, commit.email_to(self.ref_name), email_bcc, subject, body, commit.full_author_email, self.ref_name, commit.base_rev_for_display(), commit.rev, diff, filer_cmd=filer_cmd, )