Skip to content

Commit

Permalink
Cleanup changelog creation
Browse files Browse the repository at this point in the history
Extend test suite
Delete obsolete logic
  • Loading branch information
philnewm committed Nov 4, 2024
1 parent 720f072 commit 2a362ef
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 80 deletions.
80 changes: 45 additions & 35 deletions src/conversion_logic.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,43 @@
import logging
import re

from collections import namedtuple

from typing import NamedTuple

logger: logging.Logger = logging.getLogger(__name__)
Changelog: type[Changelog] = namedtuple("Changelog", "labels title number url id")


def sort_changes(changes_list: list[Changelog], changelog_label_list: list[str]) -> list[Changelog]:
class Changelog(NamedTuple):
labels: list[str]
title: str
number: int
url: str
id: int


def filter_changes_per_label(pr_data: list[dict[str, str]], changelog_label_list: list[str]) -> list[Changelog]:
"""Convert list of PR dictionaries to Changelog list
Args:
pr_data (list[dict[str, str]]): PR information and metadata
changelog_label_list (list[str]): Changelog labels
Returns:
list[Changelog]: List of changelog objects
"""

# TODO implement this logic in a more clever way
sorted_changes: list[Changelog] = []
changes_list: list[Changelog] = []

for order_label in changelog_label_list:
for change in changes_list:
if any(label == order_label for label in change.labels):
sorted_changes.append(change)
for pull_request in pr_data:
if pull_request.get("labels"):
changes_list.append(Changelog(labels=[label["name"] for label in pull_request["labels"]],
title=pull_request["title"],
number=pull_request["number"],
url=pull_request["url"],
id=pull_request["id"],
)
)

return sorted_changes
return changes_list


# INFO currently not in use
Expand Down Expand Up @@ -52,35 +71,26 @@ def get_changelog(pr_data, changelog_start="## Changelog", heading="##"):
return changelog_lines


def filter_changes_per_label(pr_data: list[dict[str, str]], changelog_label_list: list[str]) -> list[Changelog]:

changes_list: list[Changelog] = []

for pull_request in pr_data:

# TODO refactor this to become more readable
label_list: list[str] = [label["name"] for label in pull_request["labels"] if label["name"] in changelog_label_list]
if label_list:
changes_list.append(Changelog(label_list, pull_request["title"], pull_request["number"], pull_request["url"], pull_request["id"]))
def format_changelog_markdown(changes: list[Changelog], changelog_label_list: list[str]) -> str:
"""Create markdown formatted changelog.
return changes_list
Args:
changes (list[Changelog]): Changelogs in a list
changelog_label_list (list[str]): Label list to control order and filtering
Returns:
str: Markdown formatted string
"""

def build_changelog_markdown(changes: list[Changelog]) -> str:
changelog = "# Changelog"
previous_labels: list[str] = []

# TODO implement this logic in a more clever way, checkout `from itertools import groupby`
for change in changes:
current_labels: list[str] = change.labels

if not any(label in previous_labels for label in current_labels):
label: str = change.labels[0].removeprefix("type: ")
changelog += f"\n\n## {label.capitalize()}\n\n"

changelog += f"* {change.title} - [{change.number}]({change.url})\n"
for label in changelog_label_list:
formatted_label: str = label.removeprefix("type: ").capitalize()
changelog += f"\n\n## {formatted_label}\n\n"

previous_labels = current_labels
for change in changes:
if change.labels[0] == label:
changelog += f"* {change.title} - [{change.number}]({change.url})\n"

return changelog

Expand Down Expand Up @@ -128,7 +138,7 @@ def csv_string_to_list(input: str) -> list[str]:
return []


def get_version_increment(pr_label_list: list, patch_bump_list: list=[], minor_bump_list: list=[], major_bump_list: list=[]):
def get_version_increment(pr_label_list: list[str], patch_bump_list: list[str]=[], minor_bump_list: list[str]=[], major_bump_list: list[str]=[]):
"""Figure out version increment based on PR labels.
Args:
Expand Down
16 changes: 16 additions & 0 deletions tests/formatted_changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Changelog

## Enhancement

* Validate unique names only within the instance not in full scene - [70](https://github.com/ynput/ayon-maya/pull/70)

## Bug

* AY-6654 Look: Fix None values in collecting and applying attributes - [89](https://github.com/ynput/ayon-maya/pull/89)
* Fix settings for Maya USD Animation Extractor - [77](https://github.com/ynput/ayon-maya/pull/77)
* Improve applying render resolution and aspect ratio on render settings reset - [75](https://github.com/ynput/ayon-maya/pull/75)
* Maya Scene exports do not default to including nodes that not children of members - [71](https://github.com/ynput/ayon-maya/pull/71)

## Maintenance

* Skip extraction of active view for automatic tests - [126](https://github.com/ynput/ayon-maya/pull/126)
95 changes: 50 additions & 45 deletions tests/test_github_query.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Any, Literal
from typing import Any, Literal, List
import json
import pytest

from src import conversion_logic

@pytest.fixture
def pr_api_output() -> list[dict[str, Any]]:
def pr_api_output() -> List[dict[str, Any]]:
return [
{
"body": "# Bug Fix PR Template\r\n\r\n[ x] Feature/Enhancement<br>\r\n[ ] Bugfix<br>\r\n[ ] Documentation update<br>\r\n\r\n## Summary\r\n\r\n<!--Provide a concise description of your changes and implementation.-->\r\n\r\n## Root Cause Analysis\r\n\r\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)<br>\r\n<!--Detail the reason for your change and which benefits result from it.-->\r\n\r\n## Changes\r\n\r\n<!--Outline the changes made in a list.-->\r\n* Add more test\r\n* Was very important\r\n* Needed to add this here\r\n\r\n## Testing Strategy\r\n\r\n<!--Explain how the fix has been tested to ensure the bug is resolved without introducing new issues.-->\r\n\r\n## Checklist\r\n\r\n* [ x] The fix has been locally tested\r\n* [ x] New unit tests have been added to prevent future regressions\r\n* [ x] The documentation has been updated if necessary\r\n\r\n## Additional Notes\r\n\r\n<!--Any further information needed to understand the fix or its impact.-->",
Expand Down Expand Up @@ -55,17 +55,22 @@ def pr_api_output_missing_label():
]

@pytest.fixture
def major_bump():
def major_bump() -> List[str]:
return ["epic"]

@pytest.fixture
def major_bump_no_list():
def major_bump_no_list() -> Literal['epic']:
return "epic"

@pytest.fixture
def merged_pr_samples():
with open("merged_pr_query.json") as file:
return json.load(file)

@pytest.fixture
def changelog_markdown() -> str:
with open("formatted_changelog.md") as file:
return file.read()

@pytest.fixture
def minor_bump() -> list[str]:
Expand All @@ -84,11 +89,7 @@ def pr_labels_enhancement() -> list[str]:
return ["bugfix", "documentation", "feature", "enhancement"]

@pytest.fixture
def pr_labels_epic():
return ["bugfix", "documentation", "feature", "enhancement", "epic"]

@pytest.fixture
def pr_labels_epic():
def pr_labels_epic() -> List[str]:
return ["bugfix", "documentation", "feature", "enhancement", "epic"]

@pytest.fixture
Expand All @@ -111,14 +112,6 @@ def csv_string_spaces() -> Literal['bugfix, enhancement, feature']:
def csv_string_no_spaces() -> Literal['bugfix,enhancement,feature']:
return "bugfix,enhancement,feature"

@pytest.fixture
def csv_string_no_spaces() -> Literal['bugfix,enhancement,feature']:
return "bugfix,enhancement,feature"

@pytest.fixture
def csv_string_no_comma() -> Literal['bugfix']:
return "bugfix"

@pytest.fixture
def csv_string_no_comma() -> Literal['bugfix']:
return "bugfix"
Expand All @@ -127,51 +120,59 @@ def csv_string_no_comma() -> Literal['bugfix']:
def csv_string_empty() -> Literal['']:
return ""

@pytest.fixture
def changelog_label_list() -> list[str]:
return ["type: enhancement", "type: bug", "type: maintenance"]

@pytest.fixture
def changelog_exclude_label_list() -> List[str]:
return ["sponsored"]


# Get PR Label test-cases

def test_get_labels(pr_api_output):
labels = conversion_logic.filter_unique_labels(pr_data=pr_api_output)
def test_get_labels(pr_api_output: List[dict[str, Any]]) -> None:
labels: List[str] = conversion_logic.filter_unique_labels(pr_data=pr_api_output)

assert isinstance(labels, list)
assert set(labels) == {"bugfix", "enhancement"}

def test_get_labels_missing_input(pr_api_output_missing_label):
def test_get_labels_missing_input(pr_api_output_missing_label) -> None:
labels = conversion_logic.filter_unique_labels(pr_data=pr_api_output_missing_label)

assert labels == []


# Convert repo label list

def test_csv_string_to_list_spaces(csv_string_spaces):
string_list = conversion_logic.csv_string_to_list(csv_string_spaces)
string_list = conversion_logic.csv_string_to_list(csv_string_spaces)
def test_csv_string_to_list_spaces(csv_string_spaces: Literal['bugfix, enhancement, feature']) -> None:
string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_spaces)
string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_spaces)

assert string_list == ["bugfix", "enhancement", "feature"]

def test_csv_string_to_list_no_spaces(csv_string_no_spaces):
string_list = conversion_logic.csv_string_to_list(csv_string_no_spaces)
string_list = conversion_logic.csv_string_to_list(csv_string_no_spaces)
def test_csv_string_to_list_no_spaces(csv_string_no_spaces: Literal['bugfix,enhancement,feature']) -> None:
string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_no_spaces)
string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_no_spaces)

assert string_list == ["bugfix", "enhancement", "feature"]

def test_csv_string_to_list_no_comma(csv_string_no_comma):
string_list = conversion_logic.csv_string_to_list(csv_string_no_comma)
string_list = conversion_logic.csv_string_to_list(csv_string_no_comma)
def test_csv_string_to_list_no_comma(csv_string_no_comma: Literal['bugfix']) -> None:
string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_no_comma)
string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_no_comma)

assert string_list == ["bugfix"]

def test_csv_string_to_list_empty(csv_string_empty):
string_list = conversion_logic.csv_string_to_list(csv_string_empty)
string_list = conversion_logic.csv_string_to_list(csv_string_empty)
def test_csv_string_to_list_empty(csv_string_empty: Literal['']) -> None:
string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_empty)
string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_empty)

assert string_list == []


# Version Increment test-cases

def test_get_version_increment_patch(minor_bump, patch_bump, pr_labels_bug):
def test_get_version_increment_patch(minor_bump: List[str], patch_bump: List[str], pr_labels_bug: List[str]) -> None:
increment = conversion_logic.get_version_increment(
pr_label_list=pr_labels_bug,
patch_bump_list=patch_bump,
Expand All @@ -180,7 +181,7 @@ def test_get_version_increment_patch(minor_bump, patch_bump, pr_labels_bug):

assert increment == "patch"

def test_get_version_increment_minor(minor_bump, patch_bump, pr_labels_enhancement):
def test_get_version_increment_minor(minor_bump: List[str], patch_bump: List[str], pr_labels_enhancement: List[str]) -> None:
increment = conversion_logic.get_version_increment(
pr_label_list=pr_labels_enhancement,
patch_bump_list=patch_bump,
Expand All @@ -189,7 +190,7 @@ def test_get_version_increment_minor(minor_bump, patch_bump, pr_labels_enhanceme

assert increment == "minor"

def test_get_version_increment_minor(minor_bump, patch_bump, major_bump, pr_labels_epic):
def test_get_version_increment_minor(minor_bump: List[str], patch_bump: List[str], major_bump: List[str], pr_labels_epic: List[str]) -> None:
increment = conversion_logic.get_version_increment(
pr_label_list=pr_labels_epic,
patch_bump_list=patch_bump,
Expand All @@ -199,7 +200,7 @@ def test_get_version_increment_minor(minor_bump, patch_bump, major_bump, pr_labe

assert increment == "major"

def test_get_version_increment_wrong_labels(minor_bump, patch_bump, pr_labels_wrong_labels):
def test_get_version_increment_wrong_labels(minor_bump: List[str], patch_bump: List[str], pr_labels_wrong_labels: List[str]):
increment = conversion_logic.get_version_increment(
pr_label_list=pr_labels_wrong_labels,
patch_bump_list=patch_bump,
Expand All @@ -208,7 +209,7 @@ def test_get_version_increment_wrong_labels(minor_bump, patch_bump, pr_labels_wr

assert increment == ""

def test_get_version_increment_none(minor_bump, patch_bump, pr_labels_none):
def test_get_version_increment_none(minor_bump: List[str], patch_bump: List[str], pr_labels_none: None) -> None:
increment = conversion_logic.get_version_increment(
pr_label_list=pr_labels_none,
patch_bump_list=patch_bump,
Expand All @@ -217,7 +218,7 @@ def test_get_version_increment_none(minor_bump, patch_bump, pr_labels_none):

assert increment == ""

def test_get_version_increment_empty_list(minor_bump, patch_bump, pr_labels_empty_list):
def test_get_version_increment_empty_list(minor_bump: List[str], patch_bump: List[str], pr_labels_empty_list: List[Any]) -> None:
increment = conversion_logic.get_version_increment(
pr_label_list=pr_labels_empty_list,
patch_bump_list=patch_bump,
Expand All @@ -226,7 +227,7 @@ def test_get_version_increment_empty_list(minor_bump, patch_bump, pr_labels_empt

assert increment == ""

def test_get_version_increment_no_list(minor_bump, patch_bump, major_bump_no_list, pr_labels_epic):
def test_get_version_increment_no_list(minor_bump: List[str], patch_bump: List[str], major_bump_no_list: Literal['epic'], pr_labels_epic: List[str]) -> None:
with pytest.raises(ValueError, match="must be a list"):
conversion_logic.get_version_increment(
pr_label_list=pr_labels_epic,
Expand All @@ -238,10 +239,14 @@ def test_get_version_increment_no_list(minor_bump, patch_bump, major_bump_no_lis

# Changelog test-cases

def test_changer_pert_label(merged_pr_samples: dict[str, str]) -> None:
changelog_labels: list[str] = ["type: bug", "type: enhancement", "type: maintenance"]
filtered_results: list[Changelog] = conversion_logic.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_labels)
def test_filter_changes_per_label_types(merged_pr_samples: List[dict[str, str]], changelog_label_list: List[str]) -> None:
filtered_pr_list: List[conversion_logic.Changelog] = conversion_logic.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_label_list)

assert all(isinstance(changelog, conversion_logic.Changelog) for changelog in filtered_pr_list)


def test_format_changelog_markdown(merged_pr_samples: List[dict[str, str]], changelog_label_list: List[str], changelog_markdown: str) -> None:
filtered_pr_list: List[conversion_logic.Changelog] = conversion_logic.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_label_list)
changelog_result: str = conversion_logic.format_changelog_markdown(changes=filtered_pr_list, changelog_label_list=changelog_label_list)

for result in filtered_results:
for label in result.labels:
assert label in changelog_labels
assert changelog_result == changelog_result

0 comments on commit 2a362ef

Please sign in to comment.