Ejemplo n.º 1
0
def all_refs(split=False, git=git):
    """Return a tuple of (local branches, remote branches, tags)."""
    local_branches = []
    remote_branches = []
    tags = []
    triple = lambda x, y: (x, len(x) + 1, y)
    query = (triple('refs/tags', tags),
             triple('refs/heads', local_branches),
             triple('refs/remotes', remote_branches))
    cmdout = core.decode(git.for_each_ref(format='%(refname)'))
    for ref in cmdout.splitlines():
        for prefix, prefix_len, dst in query:
            if ref.startswith(prefix) and not ref.endswith('/HEAD'):
                dst.append(ref[prefix_len:])
                continue
    if split:
        return local_branches, remote_branches, tags
    else:
        return local_branches + remote_branches + tags
Ejemplo n.º 2
0
def for_each_ref_basename(refs, git=git):
    """Return refs starting with 'refs'."""
    git_output = git.for_each_ref(refs, format='%(refname)')
    output = core.decode(git_output).splitlines()
    non_heads = filter(lambda x: not x.endswith('/HEAD'), output)
    return map(lambda x: x[len(refs) + 1:], non_heads)
Ejemplo n.º 3
0
    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,
        )