From 9bb9d0712b31efb10a1b68192690b05b32b631e0 Mon Sep 17 00:00:00 2001 From: Heinz-Alexander Fuetterer Date: Sat, 14 Dec 2024 21:45:01 +0100 Subject: [PATCH] build: update psr templates After updating python-semantic-release the custom changelog and release notes templates stopped working as expected. The changelog and release notes generated for 0.10.0 e.g. did not display feature commits. This commit introduces modified versions of the new default templates of python-semantic-release. --- .github/templates/.changes.j2 | 16 -- .../.components/changelog_header.md.j2 | 20 +++ .../.components/changelog_init.md.j2 | 34 ++++ .../.components/changelog_update.md.j2 | 72 ++++++++ .github/templates/.components/changes.md.j2 | 93 ++++++++++ .github/templates/.components/custom.md.j2 | 15 ++ .github/templates/.components/macros.md.j2 | 170 ++++++++++++++++++ .../.components/release_notes_footer.md.j2 | 12 ++ .../.components/unreleased_changes.md.j2 | 18 ++ .../.components/versioned_changes.md.j2 | 27 +++ .github/templates/.release_notes.md.j2 | 73 ++++++-- .github/templates/CHANGELOG.md.j2 | 41 +++-- CHANGELOG.md | 146 +++++++++++++-- pyproject.toml | 12 +- 14 files changed, 679 insertions(+), 70 deletions(-) delete mode 100644 .github/templates/.changes.j2 create mode 100644 .github/templates/.components/changelog_header.md.j2 create mode 100644 .github/templates/.components/changelog_init.md.j2 create mode 100644 .github/templates/.components/changelog_update.md.j2 create mode 100644 .github/templates/.components/changes.md.j2 create mode 100644 .github/templates/.components/custom.md.j2 create mode 100644 .github/templates/.components/macros.md.j2 create mode 100644 .github/templates/.components/release_notes_footer.md.j2 create mode 100644 .github/templates/.components/unreleased_changes.md.j2 create mode 100644 .github/templates/.components/versioned_changes.md.j2 diff --git a/.github/templates/.changes.j2 b/.github/templates/.changes.j2 deleted file mode 100644 index 076ac09..0000000 --- a/.github/templates/.changes.j2 +++ /dev/null @@ -1,16 +0,0 @@ -{%- set commit_type_heading_mapping = ( - ("breaking", "Breaking Changes"), - ("feature", "Features"), - ("fix", "Bug Fixes"), - ("performance", "Performance improvements"), - ("refactor", "Code Refactoring"), - ("test", "Testing"), - ("documentation", "Documentation"), -) -%} - -{% for commit_type, heading in commit_type_heading_mapping if commit_type in release["elements"] %} -### {{ heading }} - -{% for commit in release["elements"][commit_type] -%} -- {% if commit.scope %}**{{ commit.scope }}:** {% endif %}{{ commit.descriptions[0] }} ([`{{ commit.short_hash }}`]({{ commit.hexsha|commit_hash_url }})) -{% endfor %}{% endfor %} diff --git a/.github/templates/.components/changelog_header.md.j2 b/.github/templates/.components/changelog_header.md.j2 new file mode 100644 index 0000000..15e41e8 --- /dev/null +++ b/.github/templates/.components/changelog_header.md.j2 @@ -0,0 +1,20 @@ +{# + +This template is adapted from: +"python-semantic-release" (MIT License) +https://github.com/python-semantic-release/python-semantic-release/blob/v9.17.0/src/semantic_release/data/templates/angular/md/.components/changelog_header.md.j2 + +#} +# Changelog + +All notable changes to this project will be documented in this file. + +This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). See +[conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) for commit guidelines. +{% if ctx.changelog_mode == "update" +%}{# # IMPORTANT: add insertion flag for next version update +#}{{ + insertion_flag ~ "\n" + +}}{% endif +%} diff --git a/.github/templates/.components/changelog_init.md.j2 b/.github/templates/.components/changelog_init.md.j2 new file mode 100644 index 0000000..13ffc99 --- /dev/null +++ b/.github/templates/.components/changelog_init.md.j2 @@ -0,0 +1,34 @@ +{# + +This template is adapted from: +"python-semantic-release" (MIT License) +https://github.com/python-semantic-release/python-semantic-release/blob/v9.17.0/src/semantic_release/data/templates/angular/md/.components/changelog_init.md.j2 + +#}{# +This changelog template initializes a full changelog for the project, +it follows the following logic: + 1. Header + 2. Any Unreleased Details (uncommon) + 3. all previous releases except the very first release + 4. the first release + +#}{# + # Header +#}{% include "changelog_header.md.j2" +%}{# + # Any Unreleased Details (uncommon) +#}{% include "unreleased_changes.md.j2" +%}{# + # Since this is initialization, we are generating all the previous + # release notes per version. The very first release notes is specialized +#}{% if releases | length > 0 +%}{% for release in releases +%}{% if loop.last and ctx.mask_initial_release +%}{%- include "first_release.md.j2" +-%}{% else +%}{%- include "versioned_changes.md.j2" +-%}{% endif +%}{{ "\n" +}}{% endfor +%}{% endif +%} diff --git a/.github/templates/.components/changelog_update.md.j2 b/.github/templates/.components/changelog_update.md.j2 new file mode 100644 index 0000000..8d3a5c6 --- /dev/null +++ b/.github/templates/.components/changelog_update.md.j2 @@ -0,0 +1,72 @@ +{# + +This template is adapted from: +"python-semantic-release" (MIT License) +https://github.com/python-semantic-release/python-semantic-release/blob/v9.17.0/src/semantic_release/data/templates/angular/md/.components/changelog_update.md.j2 + +#}{# +This Update changelog template uses the following logic: + + 1. Read previous changelog file (ex. project_root/CHANGELOG.md) + 2. Split on insertion flag (ex. ) + 3. Print top half of previous changelog + 3. New Changes (unreleased commits & newly released) + 4. Print bottom half of previous changelog + + Note: if a previous file was not found, it does not write anything at the bottom + but render does NOT fail + +#}{% set prev_changelog_contents = prev_changelog_file | read_file | safe +%}{% set changelog_parts = prev_changelog_contents.split(insertion_flag, maxsplit=1) +%}{# +#}{% if changelog_parts | length < 2 +%}{# # insertion flag was not found, check if the file was empty or did not exist +#}{% if prev_changelog_contents | length > 0 +%}{# # File has content but no insertion flag, therefore, file will not be updated +#}{{ changelog_parts[0] +}}{% else +%}{# # File was empty or did not exist, therefore, it will be created from scratch +#}{% include "changelog_init.md.j2" +%}{% endif +%}{% else +%}{# + # Previous Changelog Header + # - Depending if there is header content, then it will separate the insertion flag + # with a newline from header content, otherwise it will just print the insertion flag +#}{% set prev_changelog_top = changelog_parts[0] | trim +%}{% if prev_changelog_top | length > 0 +%}{{ + "%s\n\n%s\n" | format(prev_changelog_top, insertion_flag | trim) + +}}{% else +%}{{ + "%s\n" | format(insertion_flag | trim) + +}}{% endif +%}{% if releases | length > 0 +%}{# # Latest Release Details +#}{% set release = releases[0] +%}{# +#}{% if releases | length == 1 and ctx.mask_initial_release +%}{# # First Release detected +#}{{ "\n" +}}{%- include "first_release.md.j2" +-%}{{ "\n" +}}{# +#}{% elif "# " ~ release.version.as_semver_tag() ~ " " not in changelog_parts[1] +%}{# # The release version is not already in the changelog so we add it +#}{{ "\n" +}}{%- include "versioned_changes.md.j2" +-%}{# +#}{% endif +%}{% endif +%}{# + # Previous Changelog Footer + # - skips printing footer if empty, which happens when the insertion_flag + # was at the end of the file (ignoring whitespace) +#}{% set previous_changelog_bottom = changelog_parts[1] | trim +%}{% if previous_changelog_bottom | length > 0 +%}{{ "\n%s\n" | format(previous_changelog_bottom) +}}{% endif +%}{% endif +%} diff --git a/.github/templates/.components/changes.md.j2 b/.github/templates/.components/changes.md.j2 new file mode 100644 index 0000000..e48f739 --- /dev/null +++ b/.github/templates/.components/changes.md.j2 @@ -0,0 +1,93 @@ +{# + +This template is adapted from: +"python-semantic-release" (MIT License) +https://github.com/python-semantic-release/python-semantic-release/blob/v9.17.0/src/semantic_release/data/templates/angular/md/.components/changes.md.j2 + +#}{% 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 +%}{% from 'custom.md.j2' import section_heading_order +%}{# +EXAMPLE: + +### Features + +- Add new feature ([#10](https://domain.com/namespace/repo/pull/10), + [`abcdef0`](https://domain.com/namespace/repo/commit/HASH)) + +- **scope**: Add new feature ([`abcdef0`](https://domain.com/namespace/repo/commit/HASH)) + +### 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(120) +%}{% set hanging_indent = hanging_indent | default(2) +%}{# +#}{% for type_ in section_heading_order if type_ in commit_objects +%}{# PREPROCESS COMMITS (order by description & format description line) +#}{% set ns = namespace(commits=commit_objects[type_]) +%}{{ apply_alphabetical_ordering_by_descriptions(ns) | default("", true) +}}{# +#}{% set commit_descriptions = [] +%}{# +#}{% for commit in ns.commits +%}{# # Add reference links to the commit summary line +#}{% set description = "- %s" | format(format_commit_summary_line(commit)) +%}{% set description = description | autofit_text_width(max_line_width, hanging_indent) +%}{{ commit_descriptions.append(description) | default("", true) +}}{% endfor +%}{# + # # PRINT SECTION (header & commits) +#}{{ "\n" +}}{{ "### %s\n" | format(type_ | title) +}}{{ "\n" +}}{{ "%s\n" | format(commit_descriptions | unique | join("\n")) +}}{% endfor +-%} +{# + # # Determine if any commits have a breaking change + # # commit_objects is a dictionary of strings to a list of commits { "Features", [ParsedCommit(), ...] } +#}{% set breaking_commits = [] +%}{% for commits in commit_objects.values() +%}{# # Filter out breaking change commits that have no breaking descriptions +#}{{ breaking_commits.extend( + commits | rejectattr("error", "defined") | selectattr("breaking_descriptions.0") + ) | default("", true) +}}{% endfor +%}{# +#}{% 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 | 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 +-%} diff --git a/.github/templates/.components/custom.md.j2 b/.github/templates/.components/custom.md.j2 new file mode 100644 index 0000000..36036b7 --- /dev/null +++ b/.github/templates/.components/custom.md.j2 @@ -0,0 +1,15 @@ +{# Ref: https://github.com/python-semantic-release/python-semantic-release/issues/1122#issuecomment-2542518505 + +The types in the section header order corresponds to the ones defined in +PSR's angular commit parser: +https://github.com/python-semantic-release/python-semantic-release/blob/7b3f71697ccfbaef884e1e754b6364e974b134cf/src/semantic_release/commit_parser/angular.py#L46 + +#} +{% set section_heading_order = [ + "features", + "bug fixes", + "performance improvements", + "refactoring", + "testing", + "documentation", +] %} diff --git a/.github/templates/.components/macros.md.j2 b/.github/templates/.components/macros.md.j2 new file mode 100644 index 0000000..27daa84 --- /dev/null +++ b/.github/templates/.components/macros.md.j2 @@ -0,0 +1,170 @@ +{# + +This template is adapted from: +"python-semantic-release" (MIT License) +https://github.com/python-semantic-release/python-semantic-release/blob/v9.17.0/src/semantic_release/data/templates/angular/md/.components/macros.md.j2 + +#}{# + MACRO: format a inline link reference in Markdown +#}{% macro format_link(link, label) +%}{{ "[%s](%s)" | format(label, link) +}}{% endmacro +%} + + +{# + MACRO: commit message links or PR/MR links of commit +#}{% macro commit_msg_links(commit) +%}{% if commit.error is undefined +%}{% set commit_hash_link = format_link( + commit.hexsha | commit_hash_url, + "`%s`" | format(commit.short_hash) + ) +%}{# +#}{% set summary_line = commit.descriptions[0] | safe +%}{% set summary_line = [ + summary_line.split(" ", maxsplit=1)[0] | capitalize, + summary_line.split(" ", maxsplit=1)[1] + ] | join(" ") +%}{# +#}{% if commit.linked_merge_request != "" +%}{# # Add PR references with a link to the PR +#}{% set pr_num = commit.linked_merge_request +%}{% set pr_link = format_link(pr_num | pull_request_url, pr_num) +%}{# + # breaking change v10, remove summary line replacers as PSR will do it for us +#}{% set summary_line = summary_line | replace("(pull request", "(") | replace("(" ~ pr_num ~ ")", "") | trim +%}{% set summary_line = "%s (%s, %s)" | format( + summary_line, + pr_link, + commit_hash_link, + ) +%}{# + # DEFAULT: No PR identifier found, so just append commit hash as url to the commit summary_line +#}{% else +%}{% set summary_line = "%s (%s)" | format(summary_line, commit_hash_link) +%}{% endif +%}{# + # Return the modified summary_line +#}{{ summary_line +}}{% endif +%}{% endmacro +%} + + +{# + MACRO: format commit summary line +#}{% macro format_commit_summary_line(commit) +%}{# # Check for Parsing Error +#}{% if commit.error is undefined +%}{# + # # Add any message links to the commit summary line +#}{% set summary_line = commit_msg_links(commit) +%}{# +#}{% if commit.scope +%}{% set summary_line = "**%s**: %s" | format(commit.scope, summary_line) +%}{% endif +%}{# + # # Return the modified summary_line +#}{{ summary_line +}}{# +#}{% else +%}{# # Return the first line of the commit if there was a Parsing Error +#}{{ (commit.commit.message | string).split("\n", maxsplit=1)[0] +}}{% endif +%}{% endmacro +%} + + +{# + 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 + - 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_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='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,descriptions.0') +%}{{ ordered_commits.append(commit) | default("", true) +}}{% endfor +%}{# + # # Return the ordered commits +#}{% 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 +%} diff --git a/.github/templates/.components/release_notes_footer.md.j2 b/.github/templates/.components/release_notes_footer.md.j2 new file mode 100644 index 0000000..6d78efa --- /dev/null +++ b/.github/templates/.components/release_notes_footer.md.j2 @@ -0,0 +1,12 @@ +## Installation + +You can install this version via pip from [PyPI](https://pypi.org/project/{{ repo_name }}/{{ version }}/): + +```console +python -m pip install {{ repo_name }}=={{ version }} +``` +or pull the Docker image from [GHCR](https://github.com/{{ repo_owner }}/{{ repo_name }}/pkgs/container/{{ repo_name }}): + +```console +docker pull ghcr.io/{{ repo_owner }}/{{ repo_name }}:{{ version }} +``` diff --git a/.github/templates/.components/unreleased_changes.md.j2 b/.github/templates/.components/unreleased_changes.md.j2 new file mode 100644 index 0000000..9e3f220 --- /dev/null +++ b/.github/templates/.components/unreleased_changes.md.j2 @@ -0,0 +1,18 @@ +{# + +This template is adapted from: +"python-semantic-release" (MIT License) +https://github.com/python-semantic-release/python-semantic-release/blob/v9.17.0/src/semantic_release/data/templates/angular/md/.components/unreleased_changes.md.j2 + +#}{# + +We just display a comparison url from the last release to the main branch, e.g. + +## [Unreleased](https://github.com/afuetterer/python-re3data/compare/0.10.0...main) + +#}{% set version_tag = releases[0].version.as_tag() +%}{% set version_comparison_url = version_tag | compare_url("main") +-%} +## [Unreleased]({{ version_comparison_url }}) +{{ "\n" +}} diff --git a/.github/templates/.components/versioned_changes.md.j2 b/.github/templates/.components/versioned_changes.md.j2 new file mode 100644 index 0000000..a8311a1 --- /dev/null +++ b/.github/templates/.components/versioned_changes.md.j2 @@ -0,0 +1,27 @@ +{# + +This template is adapted from: +"python-semantic-release" (MIT License) +https://github.com/python-semantic-release/python-semantic-release/blob/v9.17.0/src/semantic_release/data/templates/angular/md/.components/versioned_changes.md.j2 + +#}{# +## vX.X.X (YYYY-MMM-DD) + +#}{% set curr_release_index = releases.index(release) +%}{% set prev_release_index = curr_release_index + 1 +%}{% if 'compare_url' is filter and prev_release_index < releases | length +%}{% set prev_version_tag = releases[prev_release_index].version.as_tag() +%}{% set new_version_tag = release.version.as_tag() +%}{% set version_comparison_url = prev_version_tag | compare_url(new_version_tag) +%}{% endif +-%} +{{ + "## [%s](%s) (%s)" | format( + release.version.as_tag(), + version_comparison_url, + release.tagged_date.strftime("%Y-%m-%d"), + ) +}}{% set commit_objects = release["elements"] +%} +{% include "changes.md.j2" +-%} diff --git a/.github/templates/.release_notes.md.j2 b/.github/templates/.release_notes.md.j2 index 5cfedfa..101729d 100644 --- a/.github/templates/.release_notes.md.j2 +++ b/.github/templates/.release_notes.md.j2 @@ -1,19 +1,64 @@ -{%- set releases = context.history.released.items() | list -%} -{%- set prev_version = releases[1][0] -%} -## Release Notes -{% include ".changes.j2" %} -{{ "**Full Changelog**: (%s)" | format(prev_version | compare_url(version)) }} +{# -## Installation +This template is adapted from: +"python-semantic-release" (MIT License) +https://github.com/python-semantic-release/python-semantic-release/blob/v9.17.0/src/semantic_release/data/templates/angular/md/.release_notes.md.j2 -You can install this version via pip from [PyPI](https://pypi.org/project/python-re3data/{{ version }}/): +#}{# EXAMPLE: -```console -python -m pip install python-re3data=={{ version }} -``` +### Features -or pull the Docker image from [GHCR](https://github.com/afuetterer/python-re3data/pkgs/container/python-re3data): +- Add new feature ([#10](https://domain.com/namespace/repo/pull/10), + [`abcdef0`](https://domain.com/namespace/repo/commit/HASH)) -```console -docker pull ghcr.io/afuetterer/python-re3data:{{ version }} -``` +- **scope**: Add new feature + ([`abcdef0`](https://domain.com/namespace/repo/commit/HASH)) + +### Bug Fixes + +- 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) + +#}{# # Set line width to 1000 to avoid wrapping as GitHub will handle it +#}{% set max_line_width = max_line_width | default(1000) +%}{% set hanging_indent = hanging_indent | default(2) +%}{% set releases = context.history.released.values() | list +%}{% set curr_release_index = releases.index(release) +%}{% set prev_release_index = curr_release_index + 1 +%}{# +#}{% if 'compare_url' is filter and prev_release_index < releases | length +%}{% set prev_version_tag = releases[prev_release_index].version.as_tag() +%}{% set new_version_tag = release.version.as_tag() +%}{% set version_compare_url = prev_version_tag | compare_url(new_version_tag) +%}{% set detailed_changes_link = '[`{}...{}`]({})'.format( + prev_version_tag, new_version_tag, version_compare_url + ) +%}{% endif +%}{# +#}{% if releases | length == 1 and mask_initial_release +%}{# # On a first release, generate our special message +#}{% include ".components/first_release.md.j2" +%}{% else +%}{# # Not the first release so generate notes normally +#}{% include ".components/versioned_changes.md.j2" +-%}{# +#}{% if detailed_changes_link is defined +%}{{ "\n" +}}{{ "**Full Changelog**: (%s)" | format(detailed_changes_link) +}}{{ "\n\n" +}}{% endif +%}{% endif +%}{% include ".components/release_notes_footer.md.j2" +-%} diff --git a/.github/templates/CHANGELOG.md.j2 b/.github/templates/CHANGELOG.md.j2 index b7c967e..34e9a8f 100644 --- a/.github/templates/CHANGELOG.md.j2 +++ b/.github/templates/CHANGELOG.md.j2 @@ -1,21 +1,28 @@ -# Changelog +{# -All notable changes to this project will be documented in this file. +This template is adapted from: +"python-semantic-release" (MIT License) +https://github.com/python-semantic-release/python-semantic-release/blob/v9.17.0/src/semantic_release/data/templates/angular/md/CHANGELOG.md.j2 -This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). See -[conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) for commit guidelines. +#}{# + This changelog template controls which changelog creation occurs + based on which mode is provided. -{# UNRELEASED -#} -{% set last_release = context.history.released.items() | first | first -%} -## {{ "[Unreleased](%s)" | format(last_release.as_tag() | compare_url("main")) }} + Modes: + - init: Initialize a full changelog from scratch + - update: Insert new version details where the placeholder exists in the current changelog -{# RELEASED -#} -{% for version, release in context.history.released.items() -%} -{%- if loop.nextitem -%} -{%- set compare_url_ = loop.nextitem[0] | compare_url(version) -%} -## [{{ version.as_tag() }}]({{ compare_url_ }}) ({{ release.tagged_date.strftime("%Y-%m-%d") }}) -{% else -%} -## {{ version.as_tag() }} ({{ release.tagged_date.strftime("%Y-%m-%d") }}) -{% endif -%} -{% include ".changes.j2" %} -{%- endfor -%} +#}{% set insertion_flag = ctx.changelog_insertion_flag +%}{% set this_file = "CHANGELOG.md" +%}{% set unreleased_commits = ctx.history.unreleased | dictsort +%}{% set releases = ctx.history.released.values() | list +%}{# +#}{% if ctx.changelog_mode == "init" +%}{% include ".components/changelog_init.md.j2" +%}{# +#}{% elif ctx.changelog_mode == "update" +%}{% set prev_changelog_file = this_file +%}{% include ".components/changelog_update.md.j2" +%}{# +#}{% endif +-%} diff --git a/CHANGELOG.md b/CHANGELOG.md index f86d73a..b8c2179 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,62 +7,170 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased](https://github.com/afuetterer/python-re3data/compare/0.10.0...main) + + ## [0.10.0](https://github.com/afuetterer/python-re3data/compare/0.9.0...0.10.0) (2024-12-11) +### Features + +- Add return_type csv ([#182](https://github.com/afuetterer/python-re3data/pull/182), + [`4123823`](https://github.com/afuetterer/python-re3data/commit/4123823353be1fe9fc018328dd0c0542afc80ab3)) + ### Documentation -- update uv installation instructions (#227) ([`d83fe84`](https://github.com/afuetterer/python-re3data/commit/d83fe8488568ab2632ecde299da9447d680d2bee)) +- Update uv installation instructions ([#227](https://github.com/afuetterer/python-re3data/pull/227), + [`d83fe84`](https://github.com/afuetterer/python-re3data/commit/d83fe8488568ab2632ecde299da9447d680d2bee)) ## [0.9.0](https://github.com/afuetterer/python-re3data/compare/0.8.0...0.9.0) (2024-07-06) +### Features + +- **cli**: Add --outfile option for saving results to disk + ([#166](https://github.com/afuetterer/python-re3data/pull/166), + [`1e689e8`](https://github.com/afuetterer/python-re3data/commit/1e689e850b6f5c117887eb1938b1a336422e5418)) +- **client**: Add repository counting ([#158](https://github.com/afuetterer/python-re3data/pull/158), + [`c1cba53`](https://github.com/afuetterer/python-re3data/commit/c1cba53a408505c673de2aa8b4f6caddcb91cadd)) + ### Documentation -- **readme:** update key features in readme (#165) ([`2396cf5`](https://github.com/afuetterer/python-re3data/commit/2396cf59b1f2d62e917e9b335d8596aa4d3b38d6)) -- add features page (#157) ([`2348b01`](https://github.com/afuetterer/python-re3data/commit/2348b013ad16cacd8a85b72d9f6d488df1ab7f7e)) +- Add features page ([#157](https://github.com/afuetterer/python-re3data/pull/157), + [`2348b01`](https://github.com/afuetterer/python-re3data/commit/2348b013ad16cacd8a85b72d9f6d488df1ab7f7e)) +- **readme**: Update key features in readme ([#165](https://github.com/afuetterer/python-re3data/pull/165), + [`2396cf5`](https://github.com/afuetterer/python-re3data/commit/2396cf59b1f2d62e917e9b335d8596aa4d3b38d6)) ## [0.8.0](https://github.com/afuetterer/python-re3data/compare/0.7.0...0.8.0) (2024-07-03) +### Features + +- Add return_type dict ([#153](https://github.com/afuetterer/python-re3data/pull/153), + [`5894329`](https://github.com/afuetterer/python-re3data/commit/5894329ed52fb014ca4d08a0941e71a66146d446)) +- Add return_type json ([#156](https://github.com/afuetterer/python-re3data/pull/156), + [`f948d6b`](https://github.com/afuetterer/python-re3data/commit/f948d6bef533314327394dbaa250a8518af6b248)) + ## [0.7.0](https://github.com/afuetterer/python-re3data/compare/0.6.0...0.7.0) (2024-07-03) +### Features + +- Add repository filtering based on query string ([#152](https://github.com/afuetterer/python-re3data/pull/152), + [`713d4d1`](https://github.com/afuetterer/python-re3data/commit/713d4d1cd581426a95fd8d6a84f5fa4f4fff1564)) + ## [0.6.0](https://github.com/afuetterer/python-re3data/compare/0.5.0...0.6.0) (2024-07-02) +### Features + +- Add async client ([#139](https://github.com/afuetterer/python-re3data/pull/139), + [`b0c4a48`](https://github.com/afuetterer/python-re3data/commit/b0c4a48b03bc42bec194f4b6c8aa4f1f54d75231)) + ### Documentation -- add installation guide (#129) ([`0de3b5e`](https://github.com/afuetterer/python-re3data/commit/0de3b5e2f93bf162f3c94b1b3eb18cf522962725)) -- enable permalinks for headings (#132) ([`89d0a3d`](https://github.com/afuetterer/python-re3data/commit/89d0a3d2434db5eab1323843a25d6fcb1f903703)) +- Add installation guide ([#129](https://github.com/afuetterer/python-re3data/pull/129), + [`0de3b5e`](https://github.com/afuetterer/python-re3data/commit/0de3b5e2f93bf162f3c94b1b3eb18cf522962725)) +- Enable permalinks for headings ([#132](https://github.com/afuetterer/python-re3data/pull/132), + [`89d0a3d`](https://github.com/afuetterer/python-re3data/commit/89d0a3d2434db5eab1323843a25d6fcb1f903703)) ## [0.5.0](https://github.com/afuetterer/python-re3data/compare/0.4.0...0.5.0) (2024-06-05) +### Breaking Changes + +- Set up resources ([#109](https://github.com/afuetterer/python-re3data/pull/109), + [`0d766d2`](https://github.com/afuetterer/python-re3data/commit/0d766d24f46d6ec9182ac89a743ed5fa88b6a274)) + +### Features + +- Add cli parameters for return_type selection ([#113](https://github.com/afuetterer/python-re3data/pull/113), + [`15668bc`](https://github.com/afuetterer/python-re3data/commit/15668bc833cc147b4c30fc0a096526ef0be8cb46)) +- Set up custom exceptions ([#108](https://github.com/afuetterer/python-re3data/pull/108), + [`a2fa099`](https://github.com/afuetterer/python-re3data/commit/a2fa099f41114ed50f8a9a64a7530cbe23d65a79)) +- **cli**: Add print_error function to highlight errors in console + ([#123](https://github.com/afuetterer/python-re3data/pull/123), + [`f242b10`](https://github.com/afuetterer/python-re3data/commit/f242b1050ab4d6c8b34874e10e170463a59cab10)) + +### Refactoring + +- Add is_eager argument to version_callback ([#106](https://github.com/afuetterer/python-re3data/pull/106), + [`eab6579`](https://github.com/afuetterer/python-re3data/commit/eab6579d3205e98b0bba4a70e3666008ade60795)) +- **cli**: Use rich.console instead of rich.print ([#122](https://github.com/afuetterer/python-re3data/pull/122), + [`a4efea0`](https://github.com/afuetterer/python-re3data/commit/a4efea0d222779642e440a6b486f17235856e721)) + +### Testing + +- Add respx mock route for /repository{id} endpoint ([#114](https://github.com/afuetterer/python-re3data/pull/114), + [`070bbf6`](https://github.com/afuetterer/python-re3data/commit/070bbf67f219a5deb04b3fbaf41ac0845553c76e)) + ## [0.4.0](https://github.com/afuetterer/python-re3data/compare/0.3.0...0.4.0) (2024-05-28) +### Features + +- Set up dockerfile ([#87](https://github.com/afuetterer/python-re3data/pull/87), + [`75d85b5`](https://github.com/afuetterer/python-re3data/commit/75d85b5ef08b6ffbda6baddd87da005d1f0481d7)) + +### Refactoring + +- **client**: Move guard clause to top of _request method ([#78](https://github.com/afuetterer/python-re3data/pull/78), + [`f3eef8b`](https://github.com/afuetterer/python-re3data/commit/f3eef8b7b4316c45a56481e68e1683855c116e35)) + ### Documentation -- add extra css for prompt (#85) ([`16545d7`](https://github.com/afuetterer/python-re3data/commit/16545d74fc7a308a2cb9144465a50b771fabb5a5)) -- add outdated message (#84) ([`7218b47`](https://github.com/afuetterer/python-re3data/commit/7218b47a027d2cc6b043417a59dca7ee458b0fa2)) -- add reference level in navigation (#80) ([`6a41547`](https://github.com/afuetterer/python-re3data/commit/6a415478032210e960d6f7ec7a8c8e840ffb84cf)) +- Add extra css for prompt ([#85](https://github.com/afuetterer/python-re3data/pull/85), + [`16545d7`](https://github.com/afuetterer/python-re3data/commit/16545d74fc7a308a2cb9144465a50b771fabb5a5)) +- Add outdated message ([#84](https://github.com/afuetterer/python-re3data/pull/84), + [`7218b47`](https://github.com/afuetterer/python-re3data/commit/7218b47a027d2cc6b043417a59dca7ee458b0fa2)) +- Add reference level in navigation ([#80](https://github.com/afuetterer/python-re3data/pull/80), + [`6a41547`](https://github.com/afuetterer/python-re3data/commit/6a415478032210e960d6f7ec7a8c8e840ffb84cf)) ## [0.3.0](https://github.com/afuetterer/python-re3data/compare/0.2.0...0.3.0) (2024-05-26) +### Features + +- **cli**: Set up repository list and get commands ([#76](https://github.com/afuetterer/python-re3data/pull/76), + [`44987e6`](https://github.com/afuetterer/python-re3data/commit/44987e6ba20f51181dbea2c2d3794a3a96ddf6a5)) + +### Testing + +- Add respx mock route for /repositories endpoint ([#75](https://github.com/afuetterer/python-re3data/pull/75), + [`59f7d58`](https://github.com/afuetterer/python-re3data/commit/59f7d58e65d91575c571e6bbea51957900424fdc)) +- Set up zenodo_id fixture for re-use ([#72](https://github.com/afuetterer/python-re3data/pull/72), + [`e926c07`](https://github.com/afuetterer/python-re3data/commit/e926c07419f2720d7d3f9c97f01285e52a52863e)) + ### Documentation -- add doi to citation.cff and badge to readme (#66) ([`2fde7ee`](https://github.com/afuetterer/python-re3data/commit/2fde7ee3e2afa7c1dbbd44bf26c8e918d6e79396)) +- Add doi to citation.cff and badge to readme ([#66](https://github.com/afuetterer/python-re3data/pull/66), + [`2fde7ee`](https://github.com/afuetterer/python-re3data/commit/2fde7ee3e2afa7c1dbbd44bf26c8e918d6e79396)) ## [0.2.0](https://github.com/afuetterer/python-re3data/compare/0.1.0...0.2.0) (2024-05-23) +### Features + +- Set up client ([#64](https://github.com/afuetterer/python-re3data/pull/64), + [`62300bc`](https://github.com/afuetterer/python-re3data/commit/62300bcf2fa2dd7f1a4c8bbaf7b7ae6bab4e9e77)) + ### Documentation -- **readme:** remove table of contents (#62) ([`8f224e8`](https://github.com/afuetterer/python-re3data/commit/8f224e8ec1819a2cbf74738af7b4e84d34d663bf)) -- **readme:** add status badge (#56) ([`cfc9f5a`](https://github.com/afuetterer/python-re3data/commit/cfc9f5a5d2b993690c5d4507603ca5bb7dac0f5e)) -- add api reference (#47) ([`9e455c4`](https://github.com/afuetterer/python-re3data/commit/9e455c490183109ca3fb7026e554ca53c7bcad12)) -- add changelog to docs (#43) ([`a167c46`](https://github.com/afuetterer/python-re3data/commit/a167c46b2b80cbefa2b7a6aee2bc0ccdbb0f6459)) -- **readme:** add pypi badges (#37) ([`f4b31a9`](https://github.com/afuetterer/python-re3data/commit/f4b31a92c2c2cc9db6c7ee484abf3e8ba6a02860)) +- Add api reference ([#47](https://github.com/afuetterer/python-re3data/pull/47), + [`9e455c4`](https://github.com/afuetterer/python-re3data/commit/9e455c490183109ca3fb7026e554ca53c7bcad12)) +- Add changelog to docs ([#43](https://github.com/afuetterer/python-re3data/pull/43), + [`a167c46`](https://github.com/afuetterer/python-re3data/commit/a167c46b2b80cbefa2b7a6aee2bc0ccdbb0f6459)) +- **readme**: Add pypi badges ([#37](https://github.com/afuetterer/python-re3data/pull/37), + [`f4b31a9`](https://github.com/afuetterer/python-re3data/commit/f4b31a92c2c2cc9db6c7ee484abf3e8ba6a02860)) +- **readme**: Add status badge ([#56](https://github.com/afuetterer/python-re3data/pull/56), + [`cfc9f5a`](https://github.com/afuetterer/python-re3data/commit/cfc9f5a5d2b993690c5d4507603ca5bb7dac0f5e)) +- **readme**: Remove table of contents ([#62](https://github.com/afuetterer/python-re3data/pull/62), + [`8f224e8`](https://github.com/afuetterer/python-re3data/commit/8f224e8ec1819a2cbf74738af7b4e84d34d663bf)) ## 0.1.0 (2024-05-20) -### Documentation +### Features -- **readme:** add short project description (#28) ([`c20f23e`](https://github.com/afuetterer/python-re3data/commit/c20f23e7b682c10c0749043e851b81cf0ec80f61)) -- **readme:** add similar projects (#23) ([`7e3e919`](https://github.com/afuetterer/python-re3data/commit/7e3e919d512d9f8556a3c45e7a6f164b9e19be9a)) -- set up python-semantic-release templates (#21) ([`bcd976a`](https://github.com/afuetterer/python-re3data/commit/bcd976aa4dcc25188dcf16f82d2a5cee475c5983)) -- **readme:** add codeql badge (#18) ([`ee6f6aa`](https://github.com/afuetterer/python-re3data/commit/ee6f6aa7dfb1f2b8b6e4d8e10bbe67b10af00c04)) +- Add initial cli ([#32](https://github.com/afuetterer/python-re3data/pull/32), + [`0b5b2c4`](https://github.com/afuetterer/python-re3data/commit/0b5b2c4a855656196d0c502de93752c780be6c40)) + +### Documentation +- Set up python-semantic-release templates ([#21](https://github.com/afuetterer/python-re3data/pull/21), + [`bcd976a`](https://github.com/afuetterer/python-re3data/commit/bcd976aa4dcc25188dcf16f82d2a5cee475c5983)) +- **readme**: Add codeql badge ([#18](https://github.com/afuetterer/python-re3data/pull/18), + [`ee6f6aa`](https://github.com/afuetterer/python-re3data/commit/ee6f6aa7dfb1f2b8b6e4d8e10bbe67b10af00c04)) +- **readme**: Add short project description ([#28](https://github.com/afuetterer/python-re3data/pull/28), + [`c20f23e`](https://github.com/afuetterer/python-re3data/commit/c20f23e7b682c10c0749043e851b81cf0ec80f61)) +- **readme**: Add similar projects ([#23](https://github.com/afuetterer/python-re3data/pull/23), + [`7e3e919`](https://github.com/afuetterer/python-re3data/commit/7e3e919d512d9f8556a3c45e7a6f164b9e19be9a)) diff --git a/pyproject.toml b/pyproject.toml index a112871..8d3bbf6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -304,13 +304,17 @@ tag_format = "{version}" version_variables = [ "src/re3data/__about__.py:__version__", ] -build_command = """ +build_command = ''' sed -i "s/^version: .*/version: $NEW_VERSION/" CITATION.cff sed -i "s/^date-released: .*/date-released: $(date "+%Y-%m-%d")/" CITATION.cff -git add CITATION.cff -""" +sed -i "s|/compare/[0-9]*\.[0-9]*\.[0-9]*...main|/compare/$NEW_VERSION...main|" CHANGELOG.md +git add CHANGELOG.md CITATION.cff +''' +changelog.mode = "update" +changelog.insertion_flag = "" changelog.template_dir = ".github/templates" -changelog.environment.keep_trailing_newline = true +changelog.exclude_commit_patterns = [ "^build", "^chore", "^style", "^ci" ] +changelog.environment.keep_trailing_newline = false [tool.typos] # Ref: https://github.com/crate-ci/typos/blob/master/docs/reference.md # add "spellchecker:disable-line" to ignore specific lines