Exemple #1
0
def add_scope(commit_msg):
    Ansi.print_info(
        wrap_width(
            "\nWhat is the scope / a noun describing section of repo? (try to keep under 15 characters)"
        ))
    text = Ansi.colour(Ansi.fg.bright_green, "Scope (optional): ")
    history_file_path = os.path.join(CONFIG_HOME_DIR, "scope_history")
    c_scope = prompt(ANSI(text),
                     history=FileHistory(history_file_path),
                     key_bindings=bindings).strip()

    if c_scope != "":
        commit_msg += "({})".format(c_scope)

    return commit_msg
Exemple #2
0
def add_footer(commit_msg):
    Ansi.print_info(
        wrap_width([
            "\nThe footer MUST contain meta-information about the commit:",
            " - Related pull-requests, reviewers, breaking changes",
            " - GitHub close/fix/resolve #issue or username/repository#issue",
            " - One piece of meta-information per-line",
            " - To submit, press the Esc key before Enter",
        ]))

    text = Ansi.colour(Ansi.fg.bright_green, "Footer (optional) ┃ ")
    history_file_path = os.path.join(CONFIG_HOME_DIR, "footer_history")
    session = PromptSession(
        completer=FooterCompleter(),
        multiline=False,
        prompt_continuation=custom_prompt_continuation,
        history=FileHistory(history_file_path),
        key_bindings=bindings,
    )
    c_footer = session.prompt(ANSI(text),
                              validator=FooterValidator(session)).strip()

    if c_footer != "":
        f_lines = c_footer.split("\n")
        f_lines = [l for l in f_lines
                   if l.strip() != ""]  # remove any lines that are empty: ""

        for i, line in enumerate(f_lines):
            line = line.strip()  # clean up extraneous whitespace

            # format each line with forced line breaks to maintain maximum line length
            f_lines[i] = "\n".join(
                textwrap.wrap(
                    line,
                    width=72,
                    break_long_words=False,
                    break_on_hyphens=False,
                    subsequent_indent="  ",
                ))

        # recombine all user defined footer lines
        formatted_footer = "\n".join(f_lines)
        commit_msg += "\n\n" + formatted_footer

    return commit_msg
Exemple #3
0
def add_description(commit_msg):
    if IS_BREAKING_CHANGE is None:
        raise ValueError(
            "Global variable `IS_BREAKING_CHANGE` has not been set.")

    if IS_BREAKING_CHANGE:
        commit_msg += "!: "
    else:
        commit_msg += ": "

    num_chars_remaining = 50 - len(commit_msg)
    Ansi.print_info(
        wrap_width(
            "\nWhat is the commit description / title. A short summary of the code changes. Use the imperative mood. No more than {} characters."
            .format(num_chars_remaining)))

    c_descr = ""

    history_file_path = os.path.join(CONFIG_HOME_DIR, "description_history")
    session = PromptSession(history=FileHistory(history_file_path),
                            key_bindings=bindings)

    length_prompt = LineLengthPrompt(num_chars_remaining, session)
    while c_descr == "":
        text = Ansi.b_green("Description: ")
        c_descr = session.prompt(
            ANSI(text),
            validator=DescriptionValidator(num_chars_remaining),
            rprompt=length_prompt.get_text,
        )

    # Sanitise
    c_descr = c_descr.strip()  # remove whitespace
    c_descr = capitaliseFirst(c_descr)  # capital first letter
    if c_descr[-1] == ".":
        c_descr = c_descr[:-1]  # remove period if last character
        c_descr = c_descr.strip()  # remove further whitespace

    commit_msg += c_descr
    return commit_msg
Exemple #4
0
def add_body(commit_msg):
    if IS_BREAKING_CHANGE is None:
        raise ValueError(
            "Global variable `IS_BREAKING_CHANGE` has not been set.")

    history_file_path = os.path.join(CONFIG_HOME_DIR, "body_history")
    session = PromptSession(
        prompt_continuation=custom_prompt_continuation,
        history=FileHistory(history_file_path),
        key_bindings=bindings,
    )
    body_validator = BodyValidator(session, IS_BREAKING_CHANGE)

    if IS_BREAKING_CHANGE:
        Ansi.print_info(
            wrap_width([
                "\nExplain what has changed in this commit to cause breaking changes.",
                "Press Esc before Enter to submit.",
            ]))
        # text = Ansi.b_green("Body (required) ┃ ")
        text = Ansi.colour(Ansi.fg.bright_green, Ansi.bold, "Body ┃ ")
    else:
        Ansi.print_info(
            wrap_width([
                "\nProvide additional contextual information about the changes here.",
                "Press Esc before Enter to submit.",
            ]))
        text = Ansi.colour(Ansi.fg.bright_green, "Body (optional) ┃ ")

    c_body = session.prompt(ANSI(text), validator=body_validator)
    c_body = c_body.strip()  # remove leading/trailing whitespace
    c_body = capitaliseFirst(c_body)  # capital first letter

    if c_body != "":
        if IS_BREAKING_CHANGE:
            c_body = "BREAKING CHANGE: " + c_body

        b_lines = c_body.split("\n")
        num_blank_lines = 0  # track the number of consecutive blank lines

        condensed_b_lines = []
        for line in b_lines:
            l_stripped = line.strip()
            if l_stripped == "":
                num_blank_lines += 1
            else:
                num_blank_lines = 0

            if num_blank_lines > 1:
                continue  # ignore any blank lines after the first
            elif l_stripped == "":
                # skip any processing and add to output if blank
                condensed_b_lines.append(l_stripped)
            else:
                # check if we are dealing with a bulleted line
                bulleted_line = False
                if l_stripped[0] in ["*", "-"]:
                    bulleted_line = True
                    line_after_bullet = l_stripped[1:].strip()
                    l_stripped = " " + l_stripped[0] + " " + line_after_bullet

                # format each line with forced line breaks to maintain maximum line length
                wrapped_line = "\n".join(
                    textwrap.wrap(
                        l_stripped,
                        width=72,
                        break_long_words=False,
                        break_on_hyphens=False,
                        subsequent_indent="   " if bulleted_line else "",
                    ))
                condensed_b_lines.append(wrapped_line)

        # recombine all user defined lines
        full_body = "\n".join(condensed_b_lines)

        # append to commit message
        commit_msg += "\n\n" + full_body

    return commit_msg
Exemple #5
0
def add_type(commit_msg):
    valid_types = {
        "feat":
        "MUST be used the commit adds/builds toward a new feature",
        "fix":
        "MUST be used when a commit represents a bug fix",
        "chore":
        "Any change to build system, dependencies, config files, scripts (no production code)",
        "docs":
        "Changes to documentation",
        "perf":
        "Changes that improves performance",
        "refactor":
        "Refactoring production code, e.g. renaming a variable/restructuring existing logic",
        "revert":
        "Any commit that explicitly reverts part/all changes introduced in a previous commit",
        "style":
        "Changes to white-space, formatting, missing semi-colons, etc.",
        "test":
        "Changes to tests e.g. adding a new/missing test or fixing/correcting existing tests",
        "wip":
        "Any code changes that are work in progress; they may not build (use these sparingly!)",
    }

    Ansi.print_info(
        wrap_width([
            "Please specify the type of this commit using one of the available keywords. Accepted types: ",
            "TAB to autocomplete...",
        ]))

    type_names = sorted(valid_types.keys())
    # create prefixes e.g. "    0  chore"
    prefixes = ["  " + str(i) + "  " + t for i, t in enumerate(type_names)]
    prefix_length = max([len(p) for p in prefixes]) + 2

    for i in range(len(type_names)):
        # type descriptions
        type_descr_width = WINDOW_WIDTH - prefix_length
        descr_lines = textwrap.wrap(
            valid_types[type_names[i]],
            width=type_descr_width,
            subsequent_indent=" " * prefix_length,
            break_long_words=False,
        )
        # ensure each line has trailing whitespace, then do join
        type_descr_str = "".join(
            map(lambda l: l.ljust(type_descr_width), descr_lines))

        # Combine type name with type description
        type_print = prefixes[i].ljust(prefix_length) + type_descr_str

        # Print the type
        Ansi.print_warning(type_print)

    valid_numeric_types = [str(n) for n in range(len(type_names))]
    valid_inputs = list(valid_types.keys()) + valid_numeric_types

    print()
    text = Ansi.b_green("Type: ")
    history_file_path = os.path.join(CONFIG_HOME_DIR, "type_history")
    c_type = prompt(
        ANSI(text),
        completer=TypeCompleter(),
        validator=TypeValidator(valid_inputs),
        history=FileHistory(history_file_path),
        key_bindings=bindings,
    )

    # Convert from number back to proper type name
    if c_type in valid_numeric_types:
        c_type = type_names[int(c_type)]

    commit_msg += c_type
    return commit_msg