Skip to content

Commit

Permalink
Add template for GitHub Releases (#67)
Browse files Browse the repository at this point in the history
* docs: Add extension that will enable GitHub Pages use for doc hosting.

* ci: Add template for generating release notes for GitHub.

* docs: Update changelog with information on template.

* ci: Update version used for semantic release
  • Loading branch information
nfelt14 authored Oct 24, 2023
1 parent 4fb480d commit 9cd3c97
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 40 deletions.
10 changes: 4 additions & 6 deletions .github/workflows/package-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,12 @@ jobs:
with:
python-version: x
check-latest: true
- name: Check for unreleased entries in the Changelog
run: python scripts/check_unreleased_changelog_items.py
- name: Copy Changelog to template directory
- name: Check for unreleased entries in the Changelog and copy files to templates
run: |
cp CHANGELOG.md python_semantic_release_templates/.previous_changelog_for_template.md
git add python_semantic_release_templates/.previous_changelog_for_template.md
python scripts/check_unreleased_changelog_items.py
git add python_semantic_release_templates
- name: Python Semantic Release
uses: python-semantic-release/python-semantic-release@v8.1.2
uses: python-semantic-release/python-semantic-release@v8.3.0
id: release
with:
force: ${{ inputs.release_level }}
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ ______________________________________________________________________

Things to be included in the next release go here.

### Added

- Added a template for rendering custom Release Notes for GitHub Releases

______________________________________________________________________

## v0.1.19 (2023-10-24)
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"sphinx.ext.todo",
"sphinx.ext.inheritance_diagram",
"sphinx.ext.graphviz",
"sphinx.ext.githubpages",
"sphinxcontrib.jquery",
"sphinxcontrib.mermaid",
"sphinx_togglebutton",
Expand Down
26 changes: 26 additions & 0 deletions python_semantic_release_templates/.macros.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{%- macro populate_variables() %}
{%- set latest_release_dict_entry = (context.history.released.items()|list)[0] %}
{%- set latest_version_number = latest_release_dict_entry[0].as_tag() %}
{%- set latest_version_date = latest_release_dict_entry[1].tagged_date.strftime("%Y-%m-%d") %}
{%- set recently_merged_prs = {} %}
{%- for type_, commits in latest_release_dict_entry[1]["elements"] | dictsort %}
{%- for commit in commits %}
{%- set pr_num = commit.commit.message.rstrip().rsplit("(#", 1)[-1].rsplit(")", 1)[0]|int %}
{%- if pr_num %}
{%- do recently_merged_prs.update({commit.commit.message.split("\n")[0].rsplit("(#", 1)[0]|safe: pr_num}) %}
{%- endif %}
{%- endfor %}
{%- endfor %}

{%- if recently_merged_prs %}
{%- set merged_prs_text_list = ["\n\n### Merged Pull Requests\n\n"] %}
{%- for message, number in recently_merged_prs.items() %}
{%- do merged_prs_text_list.append("- " ~ message ~ "([#" + number|string ~ "](" ~ number|string|pull_request_url ~ "))\n") %}
{%- endfor %}
{%- set merged_prs_text = (merged_prs_text_list|join).rstrip() %}
{%- else %}
{%- set merged_prs_text = "" %}
{%- endif %}
{%- set output = (latest_version_number, latest_version_date, merged_prs_text) %}
{{- caller(output) }}
{%- endmacro %}
Empty file.
7 changes: 7 additions & 0 deletions python_semantic_release_templates/.release_notes.md.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{%- import ".macros.j2" as macros %}

{%- call(output) macros.populate_variables() %}
{%- filter replace("Things to be included in the next release go here.", "# " + output[0] + " (" + output[1] + ")" + output[2])|replace("##", "#") %}
{%- include ".previous_release_notes_for_template.md" %}
{% endfilter %}
{%- endcall %}
32 changes: 6 additions & 26 deletions python_semantic_release_templates/CHANGELOG.md.j2
Original file line number Diff line number Diff line change
@@ -1,27 +1,7 @@
{%- set latest_release_dict_entry = (context.history.released.items()|list)[0] %}
{%- set latest_version_number = latest_release_dict_entry[0].as_tag() %}
{%- set latest_version_date = latest_release_dict_entry[1].tagged_date.strftime("%Y-%m-%d") %}
{%- set recently_merged_prs = {} %}
{%- for type_, commits in latest_release_dict_entry[1]["elements"] | dictsort %}
{%- for commit in commits %}
{%- set pr_num = commit.commit.message.rstrip().rsplit("(#", 1)[-1].rsplit(")", 1)[0]|int %}
{%- if pr_num %}
{%- do recently_merged_prs.update({commit.commit.message.split("\n")[0].rsplit("(#", 1)[0]|safe: pr_num}) %}
{%- endif %}
{%- endfor %}
{%- endfor %}
{%- import ".macros.j2" as macros %}

{%- if recently_merged_prs %}
{%- set merged_prs_text_list = ["\n\n### Merged Pull Requests\n\n"] %}
{%- for message, number in recently_merged_prs.items() %}
{%- do merged_prs_text_list.append("- " ~ message ~ "([#" + number|string ~ "](" ~ number|string|pull_request_url ~ "))\n") %}
{%- endfor %}
{%- set merged_prs_text = (merged_prs_text_list|join).rstrip() %}
{%- else %}
{%- set merged_prs_text = "" %}
{%- endif %}


{%- filter replace("Things to be included in the next release go here.", "Things to be included in the next release go here.\n\n______________________________________________________________________\n\n## " + latest_version_number + " (" + latest_version_date + ")" + merged_prs_text) %}
{%- include ".previous_changelog_for_template.md" %}
{% endfilter %}
{%- call(output) macros.populate_variables() %}
{%- filter replace("Things to be included in the next release go here.", "Things to be included in the next release go here.\n\n______________________________________________________________________\n\n## " + output[0] + " (" + output[1] + ")" + output[2]) %}
{%- include ".previous_changelog_for_template.md" %}
{% endfilter %}
{%- endcall %}
34 changes: 26 additions & 8 deletions scripts/check_unreleased_changelog_items.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
"""This script will check for unreleased entries in the CHANGELOG.md file.
It will exit with a non-zero exit code if there are no unreleased entries.
It will also copy the necessary files into the template directory to properly render the CHANGELOG
and Release Notes.
"""
import pathlib
import re
import shutil

CHANGELOG_FILENAME = "CHANGELOG.md"
CHANGELOG_FILEPATH = pathlib.Path(__file__).parent.parent / "CHANGELOG.md"
TEMPLATE_CHANGELOG_FILEPATH = (
pathlib.Path(__file__).parent.parent
/ "python_semantic_release_templates"
/ ".previous_changelog_for_template.md"
)
TEMPLATE_RELEASE_NOTES_FILEPATH = (
pathlib.Path(__file__).parent.parent
/ "python_semantic_release_templates"
/ ".previous_release_notes_for_template.md"
)


def main() -> None:
Expand All @@ -14,16 +28,17 @@ def main() -> None:
Raises:
SystemExit: Indicates no new entries were found.
"""
release_notes_content = ""
found_entries = False
with open(
pathlib.Path(__file__).parent.parent / CHANGELOG_FILENAME, encoding="utf-8"
) as changelog_file:
with CHANGELOG_FILEPATH.open(mode="r", encoding="utf-8") as changelog_file:
tracking_unreleased = False
tracking_entries = False
for line in changelog_file:
if line.startswith("___"):
tracking_unreleased = False
tracking_entries = False
if tracking_unreleased:
release_notes_content += line
if line.startswith("## Unreleased"):
tracking_unreleased = True
if tracking_unreleased and line.startswith(
Expand All @@ -37,15 +52,18 @@ def main() -> None:
)
):
tracking_entries = True
if tracking_entries:
if tracking_entries and not found_entries:
found_entries = bool(re.match(r"^- \w+", line))
if found_entries:
break

if not found_entries:
msg = f"No unreleased entries were found in {CHANGELOG_FILENAME}."
msg = f"No unreleased entries were found in {CHANGELOG_FILEPATH}."
raise SystemExit(msg)

# Copy the files to the correct location
shutil.copy(CHANGELOG_FILEPATH, TEMPLATE_CHANGELOG_FILEPATH)
with TEMPLATE_RELEASE_NOTES_FILEPATH.open("w", encoding="utf-8") as template_release_notes:
template_release_notes.write(release_notes_content.strip() + "\n")


if __name__ == "__main__":
main()

0 comments on commit 9cd3c97

Please sign in to comment.