{%   from 'macros.rst.j2' import apply_alphabetical_ordering_by_brk_descriptions
%}{% from 'macros.rst.j2' import apply_alphabetical_ordering_by_descriptions
%}{% from 'macros.rst.j2' import apply_alphabetical_ordering_by_release_notices
%}{% from 'macros.rst.j2' import extract_pr_link_reference, format_breaking_changes_description
%}{% from 'macros.rst.j2' import format_commit_summary_line, format_link_reference
%}{% from 'macros.rst.j2' import format_release_notice, generate_heading_underline
%}{#

Features
--------

* Add new feature (`#10`_, `8a7b8ec`_)

* **scope**: Add another feature (`abcdef0`_)

Bug Fixes
---------

* Fix bug (`#11`_, `8a7b8ec`_)

Breaking Changes
----------------

* With the change _____, the change causes ___ effect. Ultimately, this section
  it is a more detailed description of the breaking change. With an optional
  scope prefix like the commit messages above.

* **scope**: this breaking change has a scope to identify the part of the code that
  this breaking change applies to for better context.

Additional Release Information
------------------------------

* This is a release note that provides additional information about the release
  that is not a breaking change or a feature/bug fix.

* **scope**: this release note has a scope to identify the part of the code that
  this release note applies to for better context.

.. _#10: https://domain.com/namespace/repo/pull/10
.. _#11: https://domain.com/namespace/repo/pull/11
.. _8a7B8ec: https://domain.com/owner/repo/commit/8a7b8ec
.. _abcdef0: https://domain.com/owner/repo/commit/abcdef0

#}{%  set max_line_width = max_line_width | default(100)
%}{%  set hanging_indent = hanging_indent | default(2)
%}{#
#}{%  set post_paragraph_links = []
%}{#
#}{%  for type_, commits in commit_objects if type_ != "unknown"
%}{#    # PREPARE SECTION HEADER
#}{%    set section_header = "%s" | format(type_ | title)
%}{#
   #    # PREPROCESS COMMITS
#}{%    set ns = namespace(commits=commits)
%}{%    set _ = apply_alphabetical_ordering_by_descriptions(ns)
%}{#
#}{%    set commit_descriptions = []
%}{#
#}{%    for commit in ns.commits
%}{#      # Extract PR/MR reference if it exists and store it for later
#}{%      set pr_link_reference = extract_pr_link_reference(commit) | default("", true)
%}{%      if pr_link_reference != ""
%}{%        set _ = post_paragraph_links.append(pr_link_reference)
%}{%      endif
%}{#
   #      # Always generate a commit hash reference link and store it for later
#}{%      set commit_hash_link_reference = format_link_reference(
            commit.hexsha | commit_hash_url,
            commit.short_hash
          )
%}{%      set _ = post_paragraph_links.append(commit_hash_link_reference)
%}{#
          # Generate the commit summary line and format it for RST
          # autoformatting the reference links
#}{%      set description = "* %s" | format(format_commit_summary_line(commit))
%}{%      set description = description | convert_md_to_rst
%}{%      set description = description | autofit_text_width(max_line_width, hanging_indent)
%}{%      set _ = commit_descriptions.append(description)
%}{%    endfor
%}{#
   #    # PRINT SECTION (Header & Commits)
#}{%    if commit_descriptions | length > 0
%}{{      "\n"
}}{{      section_header ~ "\n"
}}{{      generate_heading_underline(section_header, '-')
}}{{      "\n"
}}{{      "\n%s\n" | format(commit_descriptions | unique | join("\n\n"))
}}{%    endif
%}{%  endfor
%}{#
      # Determine if there are any breaking change commits by filtering the list by breaking descriptions
      # commit_objects is a list of tuples [("Features", [ParsedCommit(), ...]), ("Bug Fixes", [ParsedCommit(), ...])]
      # HOW: Filter out breaking change commits that have no breaking descriptions
      #  1. Re-map the list to only the list of commits under the breaking category from the list of tuples
      #  2. Peel off the outer list to get a list of ParsedCommit objects
      #  3. Filter the list of ParsedCommits to only those with a breaking description
#}{%  set breaking_commits = commit_objects | map(attribute="1.0")
%}{%  set breaking_commits = breaking_commits | rejectattr("error", "defined") | selectattr("breaking_descriptions.0") | list
%}{#
#}{%  if breaking_commits | length > 0
%}{#    # PREPROCESS COMMITS
#}{%    set brk_ns = namespace(commits=breaking_commits)
%}{%    set _ = apply_alphabetical_ordering_by_brk_descriptions(brk_ns)
%}{#
#}{%    set brking_descriptions = []
%}{#
#}{%    for commit in brk_ns.commits
%}{%      set full_description = "* %s" | format(
            format_breaking_changes_description(commit).split("\n\n") | join("\n\n* ")
          )
%}{%      set _ = brking_descriptions.append(
            full_description | convert_md_to_rst | autofit_text_width(max_line_width, hanging_indent)
          )
%}{%    endfor
%}{#
   #    # PRINT BREAKING CHANGE DESCRIPTIONS (header & descriptions)
#}{{    "\n"
}}{{    "Breaking Changes\n"
}}{{    '----------------\n'
}}{{
        "\n%s\n" | format(brking_descriptions | unique | join("\n\n"))
}}{#
#}{%  endif
%}{#
      # Determine if there are any commits with release notice information by filtering the list by release_notices
      # commit_objects is a list of tuples [("Features", [ParsedCommit(), ...]), ("Bug Fixes", [ParsedCommit(), ...])]
      # HOW: Filter out commits that have no release notices
      #  1. Re-map the list to only the list of commits from the list of tuples
      #  2. Peel off the outer list to get a list of ParsedCommit objects
      #  3. Filter the list of ParsedCommits to only those with a release notice
#}{%  set notice_commits = commit_objects | map(attribute="1.0")
%}{%  set notice_commits = notice_commits | rejectattr("error", "defined") | selectattr("release_notices.0") | list
%}{#
#}{%  if notice_commits | length > 0
%}{#    PREPROCESS COMMITS
#}{%    set notice_ns = namespace(commits=notice_commits)
%}{%    set _ = apply_alphabetical_ordering_by_release_notices(notice_ns)
%}{#
#}{%    set release_notices = []
%}{#
#}{%    for commit in notice_ns.commits
%}{%      set full_description = "* %s" | format(
            format_release_notice(commit).split("\n\n") | join("\n\n* ")
          )
%}{%      set _ = release_notices.append(
            full_description | convert_md_to_rst | autofit_text_width(max_line_width, hanging_indent)
          )
%}{%    endfor
%}{#
   #    # PRINT RELEASE NOTICE INFORMATION (header & descriptions)
#}{{    "\n"
}}{{    "Additional Release Information\n"
}}{{    "------------------------------\n"
}}{{
        "\n%s\n" | format(release_notices | unique | join("\n\n"))
}}{#
#}{%  endif
%}{#
   #
   #  # PRINT POST PARAGRAPH LINKS
#}{%  if post_paragraph_links | length > 0
%}{#    # Print out any PR/MR or Issue URL references that were found in the commit messages
#}{{    "\n%s\n" | format(post_paragraph_links | unique | sort | join("\n"))
}}{%  endif
%}
