-
Notifications
You must be signed in to change notification settings - Fork 0
Fature/99 super chapters #281
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
Merged
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
de66dc7
feat: add super-chapters support for grouping chapters by label
miroslavpojer 8895bc2
feat: implement super-chapters functionality with uncategorized fallback
miroslavpojer b5b068c
fix: improve unclaimed IDs handling and normalize label input in Cust…
miroslavpojer d9291bc
Fixed review comments.
miroslavpojer d0250fd
Fix review comments.
miroslavpojer 8679c2a
feat: enhance hierarchy issue rendering logic for open and closed par…
miroslavpojer 30754f3
feat: add super-chapters support for grouping chapters by label
miroslavpojer 203a8cf
Fixed after merge issues.
miroslavpojer b93b0db
Implemented partial split by super chapter label.
miroslavpojer abfb0ff
fix: simplify comment in CustomChapters class for clarity
miroslavpojer 20cf902
Merge branch 'master' into fature/99-Super-chapters
miroslavpojer cd6cadc
refactor: streamline method calls in CustomChapters and HierarchyIssu…
miroslavpojer bafb0eb
Fixed review comments.
miroslavpojer 583978f
Self-review and reduction of pylint exceptions.
miroslavpojer 69d5b2d
Fixed black.
miroslavpojer 4666b0d
refactor: update type hints in CustomChapters and HierarchyIssueRecor…
miroslavpojer 2514d44
Fix review notes.
miroslavpojer f72bcc5
Fix review comments.
miroslavpojer 2da077c
Fix review comments.
miroslavpojer 8382e55
Fixed review comments.
miroslavpojer 85774a5
Fixed review comment.
miroslavpojer bf1d759
Add caching for super-chapters input to optimize parsing
miroslavpojer d7a11ca
Fixed review comments.
miroslavpojer a6490c2
Fix review notes.
miroslavpojer fdd73c9
Fixed review comment.
miroslavpojer bc4354a
Refactor docstrings to improve parameter descriptions and return valu…
miroslavpojer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,14 +22,15 @@ | |
| import os | ||
| import sys | ||
| import re | ||
|
|
||
| from typing import Any | ||
| import yaml | ||
|
|
||
| from release_notes_generator.utils.constants import ( | ||
| GITHUB_REPOSITORY, | ||
| GITHUB_TOKEN, | ||
| TAG_NAME, | ||
| CHAPTERS, | ||
| SUPER_CHAPTERS, | ||
| PUBLISHED_AT, | ||
| VERBOSE, | ||
| WARNINGS, | ||
|
|
@@ -59,7 +60,7 @@ | |
| ) | ||
| from release_notes_generator.utils.enums import DuplicityScopeEnum | ||
| from release_notes_generator.utils.gh_action import get_action_input | ||
| from release_notes_generator.utils.utils import normalize_version_tag | ||
| from release_notes_generator.utils.utils import normalize_labels, normalize_version_tag | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
@@ -80,6 +81,8 @@ class ActionInputs: | |
| _row_format_link_pr = None | ||
| _owner = "" | ||
| _repo_name = "" | ||
| _super_chapters_raw: str | None = None | ||
| _super_chapters_cache: list[dict[str, Any]] | None = None | ||
|
|
||
| @staticmethod | ||
| def get_github_owner() -> str: | ||
|
|
@@ -141,7 +144,7 @@ def get_from_tag_name() -> str: | |
| Get the from-tag name from the action inputs. | ||
| """ | ||
| raw = get_action_input(FROM_TAG_NAME, default="") | ||
| return normalize_version_tag(raw) # type: ignore[arg-type] | ||
| return normalize_version_tag(raw) | ||
|
|
||
| @staticmethod | ||
| def is_from_tag_name_defined() -> bool: | ||
|
|
@@ -166,11 +169,79 @@ def get_chapters() -> list[dict[str, str]]: | |
| logger.error("Error: 'chapters' input is not a valid YAML list.") | ||
| return [] | ||
| except yaml.YAMLError as exc: | ||
| logger.error("Error parsing 'chapters' input: {%s}", exc) | ||
| logger.error("Error parsing 'chapters' input: %s", exc) | ||
| return [] | ||
|
|
||
| return chapters | ||
|
|
||
| @staticmethod | ||
| def get_super_chapters() -> list[dict[str, Any]]: | ||
| """ | ||
| Get list of validated super-chapter definitions from the action inputs. | ||
|
|
||
| Each returned entry is guaranteed to have: | ||
| - 'title': str | ||
| - 'labels': list[str] (non-empty, normalized) | ||
|
|
||
| Invalid entries (non-dict, missing title, missing/empty labels) are skipped | ||
| with a warning log. | ||
| """ | ||
| # Get the 'super-chapters' input from environment variables | ||
| super_chapters_input: str = get_action_input(SUPER_CHAPTERS, default="") | ||
|
|
||
| if ( | ||
| ActionInputs._super_chapters_raw is not None | ||
| and ActionInputs._super_chapters_raw == super_chapters_input | ||
| and ActionInputs._super_chapters_cache is not None | ||
| ): | ||
| return ActionInputs._super_chapters_cache | ||
|
|
||
| # Parse the received string back to YAML array input. | ||
| try: | ||
| raw_list = yaml.safe_load(super_chapters_input) | ||
| if raw_list is None: | ||
| ActionInputs._super_chapters_raw = super_chapters_input | ||
| ActionInputs._super_chapters_cache = [] | ||
| return [] | ||
| if not isinstance(raw_list, list): | ||
| logger.error("Error: 'super-chapters' input is not a valid YAML list.") | ||
| ActionInputs._super_chapters_raw = super_chapters_input | ||
| ActionInputs._super_chapters_cache = [] | ||
| return [] | ||
| except yaml.YAMLError as exc: | ||
| logger.error("Error parsing 'super-chapters' input: %s", exc) | ||
| ActionInputs._super_chapters_raw = super_chapters_input | ||
| ActionInputs._super_chapters_cache = [] | ||
| return [] | ||
|
|
||
| result: list[dict[str, Any]] = [] | ||
| for entry in raw_list: | ||
| if not isinstance(entry, dict): | ||
| logger.warning("Skipping super-chapter definition with invalid type %s: %s", type(entry), entry) | ||
| continue | ||
| if "title" not in entry: | ||
| logger.warning("Skipping super-chapter without title key: %s", entry) | ||
| continue | ||
| title = entry["title"] | ||
| if not isinstance(title, str) or not title.strip(): | ||
| logger.warning("Skipping super-chapter with invalid title value: %r", title) | ||
| continue | ||
|
|
||
| raw_labels = entry.get("labels", entry.get("label")) | ||
| if raw_labels is None: | ||
| logger.warning("Super-chapter '%s' has no 'label' or 'labels' key; skipping", title) | ||
| continue | ||
| normalized = normalize_labels(raw_labels) | ||
| if not normalized: | ||
| logger.warning("Super-chapter '%s' labels definition empty after normalization; skipping", title) | ||
| continue | ||
|
|
||
| result.append({"title": title, "labels": normalized}) | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| logger.debug("Validated super-chapter '%s' with labels: %s", title, normalized) | ||
| ActionInputs._super_chapters_raw = super_chapters_input | ||
| ActionInputs._super_chapters_cache = result | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this cache var solving?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| return result | ||
|
|
||
|
miroslavpojer marked this conversation as resolved.
|
||
| @staticmethod | ||
| def get_hierarchy() -> bool: | ||
| """ | ||
|
|
@@ -351,19 +422,21 @@ def get_print_empty_chapters() -> bool: | |
| """ | ||
| Get the print empty chapters parameter value from the action inputs. | ||
| """ | ||
| return get_action_input(PRINT_EMPTY_CHAPTERS, "true").lower() == "true" # type: ignore[union-attr] | ||
| # mypy: string is returned as default | ||
| return get_action_input(PRINT_EMPTY_CHAPTERS, "true").lower() == "true" | ||
|
|
||
| @staticmethod | ||
| def validate_input(input_value, expected_type: type, error_message: str, error_buffer: list) -> bool: | ||
| """ | ||
| Validates the input value against the expected type. | ||
|
|
||
| @param input_value: The input value to validate. | ||
| @param expected_type: The expected type of the input value. | ||
| @param error_message: The error message to log if the validation fails. | ||
| @param error_buffer: The buffer to store the error messages. | ||
| @return: The boolean result of the validation. | ||
| Parameters: | ||
| input_value: The input value to validate. | ||
| expected_type: The expected type of the input value. | ||
| error_message: The error message to log if the validation fails. | ||
| error_buffer: The buffer to store the error messages. | ||
|
|
||
| Returns: | ||
| The boolean result of the validation. | ||
| """ | ||
|
|
||
| if not isinstance(input_value, expected_type): | ||
|
|
@@ -423,7 +496,6 @@ def validate_inputs() -> None: | |
| """ | ||
| Validates the inputs provided for the release notes generator. | ||
| Logs any validation errors and exits if any are found. | ||
| @return: None | ||
| """ | ||
| errors = [] | ||
|
|
||
|
|
@@ -540,15 +612,20 @@ def validate_inputs() -> None: | |
| logger.debug("CodeRabbit summary ignore groups: %s", coderabbit_summary_ignore_groups) | ||
| logger.debug("Hidden service chapters: %s", ActionInputs.get_hidden_service_chapters()) | ||
| logger.debug("Service chapter order: %s", ActionInputs.get_service_chapter_order()) | ||
| logger.debug("Super chapters (raw): %s", get_action_input(SUPER_CHAPTERS, default="")) | ||
|
|
||
| @staticmethod | ||
| def _detect_row_format_invalid_keywords(row_format: str, row_type: str = "Issue", clean: bool = False) -> str: | ||
| """ | ||
| Detects invalid keywords in the row format. | ||
|
|
||
| @param row_format: The row format to be checked for invalid keywords. | ||
| @param row_type: The type of row format. Default is "Issue". | ||
| @return: If clean is True, the cleaned row format. Otherwise, the original row format. | ||
| Parameters: | ||
| row_format: The row format to be checked for invalid keywords. | ||
| row_type: The type of row format. Default is "Issue". | ||
| clean: When True, strip invalid keywords from the returned string. | ||
|
|
||
| Returns: | ||
| If clean is True, the cleaned row format. Otherwise, the original row format. | ||
| """ | ||
| keywords_in_braces = re.findall(r"\{(.*?)\}", row_format) | ||
|
|
||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line means, you are always doing a planning of task in PLAN mode before implementing? If not, would this line mean, that the implementation can stop to get confirmation from user and will spent extra premium requests.
From this section I am not sure, if TDD is now way how to implement new things, since it has a big part of the copilot doc, but is Preferred workflow.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TDD block is marked Prefer (not Must), so it's being trialed rather than enforced.
Final Note: I am experimenting with this approach, here.