Skip to content

feat(default-changelog): add a separate formatted breaking changes section #1110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% from 'macros.md.j2' import apply_alphabetical_ordering_by_descriptions
%}{% from 'macros.md.j2' import format_commit_summary_line
{% from 'macros.md.j2' import apply_alphabetical_ordering_by_brk_descriptions
%}{% from 'macros.md.j2' import apply_alphabetical_ordering_by_descriptions
%}{% from 'macros.md.j2' import format_breaking_changes_description, format_commit_summary_line
%}{#
EXAMPLE:

Expand All @@ -10,11 +11,20 @@ EXAMPLE:

- **scope**: Add new feature ([`abcdef0`](https://domain.com/namespace/repo/commit/HASH))

### Fixes
### Bug Fixes

- Fix bug ([#11](https://domain.com/namespace/repo/pull/11),
[`abcdef1`](https://domain.com/namespace/repo/commit/HASH))

### 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.

#}{% set max_line_width = max_line_width | default(100)
%}{% set hanging_indent = hanging_indent | default(2)
%}{#
Expand Down Expand Up @@ -46,4 +56,37 @@ EXAMPLE:
}}{{ "\n"
}}{{ "%s\n" | format(commit_descriptions | unique | join("\n\n"))
}}{% 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)
%}{{ apply_alphabetical_ordering_by_descriptions(brk_ns) | default("", true)
}}{#
#}{% 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- ")
)
%}{{ brking_descriptions.append(
full_description | autofit_text_width(max_line_width, hanging_indent)
) | default("", true)
}}{% endfor
%}{#
# # PRINT BREAKING CHANGE DESCRIPTIONS (header & descriptions)
#}{{ "\n"
}}{{ "### BREAKING CHANGES\n"
}}{{
"\n%s\n" | format(brking_descriptions | unique | join("\n\n"))
}}{#
#}{% endif
%}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
%}{% endmacro
%}


{#
MACRO: format commit summary line
#}{% macro format_commit_summary_line(commit)
Expand All @@ -69,6 +70,44 @@
%}


{#
MACRO: format the breaking changes description by:
- Capitalizing the description
- Adding an optional scope prefix
#}{% macro format_breaking_changes_description(commit)
%}{% set ns = namespace(full_description="")
%}{#
#}{% if commit.error is undefined
%}{% for paragraph in commit.breaking_descriptions
%}{% if paragraph | trim | length > 0
%}{#
#}{% set paragraph_text = [
paragraph.split(" ", maxsplit=1)[0] | capitalize,
paragraph.split(" ", maxsplit=1)[1]
] | join(" ") | trim | safe
%}{#
#}{% set ns.full_description = [
ns.full_description,
paragraph_text
] | join("\n\n")
%}{#
#}{% endif
%}{% endfor
%}{#
#}{% set ns.full_description = ns.full_description | trim
%}{#
#}{% if commit.scope
%}{% set ns.full_description = "**%s**: %s" | format(
commit.scope, ns.full_description
)
%}{% endif
%}{% endif
%}{#
#}{{ ns.full_description
}}{% endmacro
%}


{#
MACRO: apply smart ordering of commits objects based on alphabetized summaries and then scopes
- Commits are sorted based on the commit type and the commit message
Expand All @@ -95,3 +134,31 @@
#}{% set ns.commits = ordered_commits
%}{% endmacro
%}


{#
MACRO: apply smart ordering of commits objects based on alphabetized breaking changes and then scopes
- Commits are sorted based on the commit type and the commit message
- Commits are grouped by the commit type
- parameter: ns (namespace) object with a commits list
- returns None but modifies the ns.commits list in place
#}{% macro apply_alphabetical_ordering_by_brk_descriptions(ns)
%}{% set ordered_commits = []
%}{#
# # Eliminate any ParseError commits from input set
#}{% set filtered_commits = ns.commits | rejectattr("error", "defined") | list
%}{#
# # grab all commits with no scope and sort alphabetically by the first line of the commit message
#}{% for commit in filtered_commits | rejectattr("scope") | sort(attribute='breaking_descriptions.0')
%}{{ ordered_commits.append(commit) | default("", true)
}}{% endfor
%}{#
# # grab all commits with a scope and sort alphabetically by the scope and then the first line of the commit message
#}{% for commit in filtered_commits | selectattr("scope") | sort(attribute='scope,breaking_descriptions.0')
%}{{ ordered_commits.append(commit) | default("", true)
}}{% endfor
%}{#
# # Return the ordered commits
#}{% set ns.commits = ordered_commits
%}{% endmacro
%}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@

- Fix bug (#11, [`abcdef1`](https://domain.com/namespace/repo/commit/HASH))

### 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.

---

**Detailed Changes**: [vX.X.X...vX.X.X](https://domain.com/namespace/repo/compare/vX.X.X...vX.X.X)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% from 'macros.rst.j2' import apply_alphabetical_ordering_by_descriptions
%}{% from 'macros.rst.j2' import extract_pr_link_reference
{% 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 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 generate_heading_underline
%}{#
Expand All @@ -11,11 +12,21 @@ Features

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

Fixes
-----
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.

.. _10: https://domain.com/namespace/repo/pull/10
.. _8a7B8ec: https://domain.com/owner/repo/commit/8a7b8ec
.. _abcdef0: https://domain.com/owner/repo/commit/abcdef0
Expand Down Expand Up @@ -75,6 +86,42 @@ Fixes

}}{% 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)
%}{{ apply_alphabetical_ordering_by_brk_descriptions(brk_ns) | default("", true)
}}{#
#}{% 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* ")
)
%}{{ brking_descriptions.append(
full_description | convert_md_to_rst | autofit_text_width(max_line_width, hanging_indent)
) | default("", true)
}}{% endfor
%}{#
# # PRINT BREAKING CHANGE DESCRIPTIONS (header & descriptions)
#}{{ "\n"
}}{{ "BREAKING CHANGES\n"
}}{{ '----------------\n'
}}{{
"\n%s\n" | format(brking_descriptions | 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"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,44 @@
%}


{#
MACRO: format the breaking changes description by:
- Capitalizing the description
- Adding an optional scope prefix
#}{% macro format_breaking_changes_description(commit)
%}{% set ns = namespace(full_description="")
%}{#
#}{% if commit.error is undefined
%}{% for paragraph in commit.breaking_descriptions
%}{% if paragraph | trim | length > 0
%}{#
#}{% set paragraph_text = [
paragraph.split(" ", maxsplit=1)[0] | capitalize,
paragraph.split(" ", maxsplit=1)[1]
] | join(" ") | trim | safe
%}{#
#}{% set ns.full_description = [
ns.full_description,
paragraph_text
] | join("\n\n")
%}{#
#}{% endif
%}{% endfor
%}{#
#}{% set ns.full_description = ns.full_description | trim
%}{#
#}{% if commit.scope
%}{% set ns.full_description = "**%s**: %s" | format(
commit.scope, ns.full_description
)
%}{% endif
%}{% endif
%}{#
#}{{ ns.full_description
}}{% endmacro
%}


{#
MACRO: apply smart ordering of commits objects based on alphabetized summaries and then scopes
- Commits are sorted based on the commit type and the commit message
Expand All @@ -123,3 +161,31 @@
#}{% set ns.commits = ordered_commits
%}{% endmacro
%}


{#
MACRO: apply smart ordering of commits objects based on alphabetized breaking changes and then scopes
- Commits are sorted based on the commit type and the commit message
- Commits are grouped by the commit type
- parameter: ns (namespace) object with a commits list
- returns None but modifies the ns.commits list in place
#}{% macro apply_alphabetical_ordering_by_brk_descriptions(ns)
%}{% set ordered_commits = []
%}{#
# # Eliminate any ParseError commits from input set
#}{% set filtered_commits = ns.commits | rejectattr("error", "defined") | list
%}{#
# # grab all commits with no scope and sort alphabetically by the first line of the commit message
#}{% for commit in filtered_commits | rejectattr("scope") | sort(attribute='breaking_descriptions.0')
%}{{ ordered_commits.append(commit) | default("", true)
}}{% endfor
%}{#
# # grab all commits with a scope and sort alphabetically by the scope and then the first line of the commit message
#}{% for commit in filtered_commits | selectattr("scope") | sort(attribute='scope,breaking_descriptions.0')
%}{{ ordered_commits.append(commit) | default("", true)
}}{% endfor
%}{#
# # Return the ordered commits
#}{% set ns.commits = ordered_commits
%}{% endmacro
%}
Loading