Skip to content

Commit

Permalink
Feature/53 chapter line duplicity control custom and service chapters (
Browse files Browse the repository at this point in the history
…#72)

* #53 - Chapter line duplicity control - custom and service chapters
- Implemented two new input parameters 'duplicity-scope' and 'duplicity-icon'.
- Update of unit tests for inputs validation.
- Fix several pylint issues.
- Added output example.
  • Loading branch information
miroslavpojer authored Sep 20, 2024
1 parent dff934a commit d5751a9
Show file tree
Hide file tree
Showing 16 changed files with 332 additions and 24 deletions.
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- [Select start date for closed issues and PRs](#select-start-date-for-closed-issues-and-prs)
- [Enable skipping of release notes for specific issues using label](#enable-skipping-of-release-notes-for-specific-issues-using-label)
- [Enable Service Chapters](#enable-service-chapters)
- [Showing Duplicity Lines In Chapters](#showing-duplicity-lines-in-chapters)
- [Get Started](#get-started)
- [Run Static Code Analysis](#running-static-code-analysis)
- [Run Black Tool Locally](#run-black-tool-locally)
Expand Down Expand Up @@ -50,6 +51,16 @@ Generate Release Notes action is dedicated to enhance the quality and organizati
- **Description**: A JSON string defining chapters and corresponding labels for categorization. Each chapter should have a title and a label matching your GitHub issues and PRs.
- **Required**: Yes

### `duplicity-scope`
- **Description**: Set to `custom` to allow duplicity issue lines to be shown only in custom chapters. Options: `custom`, `service`, `both`, `none`.
- **Required**: No
- **Default**: `both`

### `duplicity-icon`
- **Description**: The icon used to indicate duplicity issue lines in the release notes. Icon will be placed at the beginning of the line.
- **Required**: No
- **Default**: `🔔`

### `published-at`
- **Description**: Set to true to enable the use of the `published-at` timestamp as the reference point for searching closed issues and PRs, instead of the `created-at` date of the latest release. If first release, repository creation date is used.
- **Required**: No
Expand Down Expand Up @@ -86,7 +97,8 @@ Generate Release Notes action is dedicated to enhance the quality and organizati

## Outputs
The output of the action is a markdown string containing the release notes for the specified tag. This string can be used in subsequent steps to publish the release notes to a file, create a GitHub release, or send notifications.
TODO - review

See the [example of output](./examples/output_example.md).

## Usage Example

Expand Down Expand Up @@ -130,6 +142,8 @@ Add the following step to your GitHub workflow (in example are used non-default
{"title": "New Features 🎉", "label": "feature"},
{"title": "Bugfixes 🛠", "label": "bug"}
]'
duplicity-scope: 'service'
duplicity-icon: '🔁'
published-at: true
skip-release-notes-label: 'ignore-in-release' # changing default value of label
verbose: false
Expand Down Expand Up @@ -210,6 +224,17 @@ The action includes four specific warning chapters to highlight potential areas
Each warning chapter acts as a quality check, ensuring that the release notes are comprehensive, well-organized, and meaningful. By addressing these warnings, project maintainers can significantly improve the clarity and effectiveness of their release documentation.


### Showing Duplicity Lines In Chapters
By setting the `duplicity-scope` with one of the options, the action will show whether the duplicity issue lines are correct.
- `custom`: will show duplicity lines only in custom chapters.
- `service`: will show duplicity lines only in service chapters.
- `both`: will show duplicity lines in both custom and service chapters.
- `none`: will hide duplicity lines in all chapters.

Duplicity lines in `custom` chapters can point to potential issues with wrong labeling. In contrast, duplicity lines in `service` chapters can help maintainers identify areas with the most significant problems to address.

By setting `duplicity-icon` you can customize the icon used to indicate duplicity issue lines in the release notes. Icon will be placed at the beginning of the line. The duplicity icon is visible from **second** occurrence of the issue in the selected scope.

## Get Started

Clone the repository and navigate to the project directory:
Expand Down
10 changes: 10 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ inputs:
chapters:
description: 'JSON string defining chapters and corresponding labels for categorization.'
required: false
duplicity-scope:
description: 'Allow duplicity of issue lines in chapters. Scopes: custom, service, both, none.'
required: false
default: 'both'
duplicity-icon:
description: 'Icon to be used for duplicity warning. Icon is placed before the record line.'
required: false
default: '🔔'
published-at:
description: 'Use `published-at` timestamp instead of `created-at` as the reference point of previous Release.'
required: false
Expand Down Expand Up @@ -91,6 +99,8 @@ runs:
INPUT_GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }}
INPUT_TAG_NAME: ${{ inputs.tag-name }}
INPUT_CHAPTERS: ${{ inputs.chapters }}
INPUT_DUPLICITY_SCOPE: ${{ inputs.duplicity-scope }}
INPUT_DUPLICITY_ICON: ${{ inputs.duplicity-icon }}
INPUT_WARNINGS: ${{ inputs.warnings }}
INPUT_PUBLISHED_AT: ${{ inputs.published-at }}
INPUT_SKIP_RELEASE_NOTES_LABEL: ${{ inputs.skip-release-notes-label }}
Expand Down
76 changes: 76 additions & 0 deletions examples/output_example.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
### Breaking Changes 💥
No entries detected.

### New Features 🎉
- #22 _REQ: Submit Reviews_ in [#31](https://github.com/company/test-project/pull/31)
- Now only book purchasers can submit reviews, with mandatory text and star ratings.
- #52 _Add Tag into Release Draft_ in [#59](https://github.com/company/test-project/pull/59), [#58](https://github.com/company/test-project/pull/58), [#57](https://github.com/company/test-project/pull/57), [#56](https://github.com/company/test-project/pull/56), [#55](https://github.com/company/test-project/pull/55), [#54](https://github.com/company/test-project/pull/54), [#53](https://github.com/company/test-project/pull/53)
- #82 _Create tag after success RLS notes generation_ in [#87](https://github.com/company/test-project/pull/87), [#86](https://github.com/company/test-project/pull/86), [#85](https://github.com/company/test-project/pull/85), [#84](https://github.com/company/test-project/pull/84), [#83](https://github.com/company/test-project/pull/83)

### Bugfixes 🛠
- #33 _Example bugfix_ in [#44](https://github.com/company/test-project/pull/44), [#36](https://github.com/company/test-project/pull/36), [#35](https://github.com/company/test-project/pull/35), [#34](https://github.com/company/test-project/pull/34)
- Another solved typos. Hello from second RLS notes comment.
- Solved some typos.
- PR: #41 _Initial commit._
- Test release notes nr1
- Test release notes nr2

### Closed Issues without Pull Request ⚠️
- #3 _FEAT: User Authentication_
- #4 _FEAT: Book Browsing_
- #6 _FEAT: Shopping Cart_
- #37 _Example Issue without PR_
- #38 _Example Issue without Release notes comment_
- #88 _Test issue_

### Closed Issues without User Defined Labels ⚠️
- #1 _Initial version of project_ in [#2](https://github.com/company/test-project/pull/2)
- #7 _REQ: User Login Functionality_ in [#13](https://github.com/company/test-project/pull/13)
- #8 _REQ: User Registration Functionality_ in [#13](https://github.com/company/test-project/pull/13)
- #9 _REQ: View Book List_ in [#14](https://github.com/company/test-project/pull/14)
- #10 _REQ: Detailed Book Information_ in [#14](https://github.com/company/test-project/pull/14)
- #11 _REQ: Adding Books to Shopping Cart_ in [#15](https://github.com/company/test-project/pull/15)
- #12 _REQ: Viewing Shopping Cart Contents_ in [#15](https://github.com/company/test-project/pull/15)
- #23 _REQ: View Reviews_ in [#27](https://github.com/company/test-project/pull/27)
- #29 _Introduce workflow logic for Release notes_ in [#28](https://github.com/company/test-project/pull/28)
- #30 _Introduce Release notes logic_ in [#32](https://github.com/company/test-project/pull/32)

### Merged PRs without Issue and User Defined Labels ⚠️
- PR: #5 _BugFix - correct Issue GH folder location_
- PR: #16 _repository improvement_
- PR: #26 _Initial test headers_
- PR: #39 _Initial commit._
- PR: #40 _Initial commit._
- PR: #42 _Initial commit._
- PR: #43 _Feature/new tag_
- PR: #45 _Initial commit._
- PR: #46 _Revert "- Improved README.md (#36)"_
- PR: #47 _- Added code for received tag format and correct version increase._
- PR: #48 _Update of tag checks._
- PR: #49 _Feature/tag checks update_
- PR: #50 _Feature/tag checks update_
- PR: #51 _Feature/tag checks update_
- PR: #61 _New check implemented._
- PR: #62 _Feature/add first tag check_
- PR: #63 _New check implemented._
- PR: #64 _Experiment with improving release worklflows._
- PR: #66 _- Prepared workflow for RLS notes generation testing._

### Closed PRs without Issue and User Defined Labels ⚠️
- PR: #60 _Test change to test close of PR instead of Merge._
- PR: #65 _Fake change in PR to get PR._
- PR: #92 _Fake change._

### Merged PRs Linked to 'Not Closed' Issue ⚠️
- #20 _REQ: Search by Keywords_ in [#44](https://github.com/company/test-project/pull/44)
- 🔔 #33 _Example bugfix_ in [#44](https://github.com/company/test-project/pull/44), [#36](https://github.com/company/test-project/pull/36), [#35](https://github.com/company/test-project/pull/35), [#34](https://github.com/company/test-project/pull/34)
- Another solved typos. Hello from second RLS notes comment.
- Solved some typos.
- PR: #80 _Feature/multiline excludes_
- #81 _Test multiline excludes in filename inspector related yml_ in [#79](https://github.com/company/test-project/pull/79), [#78](https://github.com/company/test-project/pull/78), [#77](https://github.com/company/test-project/pull/77), [#76](https://github.com/company/test-project/pull/76), [#75](https://github.com/company/test-project/pull/75), [#74](https://github.com/company/test-project/pull/74), [#73](https://github.com/company/test-project/pull/73), [#72](https://github.com/company/test-project/pull/72), [#71](https://github.com/company/test-project/pull/71), [#70](https://github.com/company/test-project/pull/70), [#69](https://github.com/company/test-project/pull/69), [#68](https://github.com/company/test-project/pull/68), [#67](https://github.com/company/test-project/pull/67)

### Others - No Topic ⚠️
Previous filters caught all Issues or Pull Requests.

#### Full Changelog
https://github.com/company/test-project/commits/v0.1.0
27 changes: 27 additions & 0 deletions release_notes_generator/action_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@
RUNNER_DEBUG,
PRINT_EMPTY_CHAPTERS,
CHAPTERS_TO_PR_WITHOUT_ISSUE,
DUPLICITY_SCOPE,
DUPLICITY_ICON,
)
from release_notes_generator.utils.enums import DuplicityScopeEnum
from release_notes_generator.utils.gh_action import get_action_input

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -74,6 +77,26 @@ def get_chapters_json() -> str:
"""
return get_action_input(CHAPTERS)

@staticmethod
def get_duplicity_scope() -> DuplicityScopeEnum:
"""
Get the duplicity scope parameter value from the action inputs.
"""
duplicity_scope = get_action_input(DUPLICITY_SCOPE, "both").upper()

try:
return DuplicityScopeEnum(duplicity_scope)
except ValueError:
logger.error("Error: '%s' is not a valid DuplicityType.", duplicity_scope)
return DuplicityScopeEnum.BOTH

@staticmethod
def get_duplicity_icon() -> str:
"""
Get the duplicity icon from the action inputs.
"""
return get_action_input(DUPLICITY_ICON, "🔔")

@staticmethod
def get_published_at() -> bool:
"""
Expand Down Expand Up @@ -161,6 +184,10 @@ def validate_inputs():
except json.JSONDecodeError:
errors.append("Chapters JSON must be a valid JSON string.")

duplicity_icon = ActionInputs.get_duplicity_icon()
if not isinstance(duplicity_icon, str) or not duplicity_icon.strip() or len(duplicity_icon) != 1:
errors.append("Duplicity icon must be a non-empty string and have a length of 1.")

warnings = ActionInputs.get_warnings()
ActionInputs.validate_input(warnings, bool, "Warnings must be a boolean.", errors)

Expand Down
9 changes: 4 additions & 5 deletions release_notes_generator/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,19 @@ def build(self) -> str:
@return: The release notes as a string.
"""
logger.info("Building Release Notes")
user_defined_chapters = self.custom_chapters
user_defined_chapters.populate(self.records)
user_defined_chapters_str = user_defined_chapters.to_string()
self.custom_chapters.populate(self.records)
user_defined_chapters_str = self.custom_chapters.to_string()

user_defined_labels_nested = [
user_defined_chapters.chapters[key].labels for key in user_defined_chapters.chapters
self.custom_chapters.chapters[key].labels for key in self.custom_chapters.chapters
]
user_defined_labels = list(chain.from_iterable(user_defined_labels_nested))

if self.warnings:
service_chapters = ServiceChapters(
print_empty_chapters=self.print_empty_chapters,
user_defined_labels=user_defined_labels,
used_record_numbers=user_defined_chapters.populated_record_numbers,
used_record_numbers=self.custom_chapters.populated_record_numbers,
)
service_chapters.populate(self.records)

Expand Down
11 changes: 10 additions & 1 deletion release_notes_generator/model/custom_chapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@
#

"""
This module contains the CustomChapters class which is responsible for representing the custom chapters in the release notes.
This module contains the CustomChapters class which is responsible for representing the custom chapters in the release
notes.
"""

import json

from release_notes_generator.action_inputs import ActionInputs
from release_notes_generator.model.base_chapters import BaseChapters
from release_notes_generator.model.chapter import Chapter
from release_notes_generator.model.record import Record
from release_notes_generator.utils.enums import DuplicityScopeEnum


class CustomChapters(BaseChapters):
Expand All @@ -39,6 +42,12 @@ def populate(self, records: dict[int, Record]) -> None:
"""
for nr in records: # iterate all records
for ch in self.chapters.values(): # iterate all chapters
if nr in self.populated_record_numbers_list and ActionInputs.get_duplicity_scope() not in (
DuplicityScopeEnum.CUSTOM,
DuplicityScopeEnum.BOTH,
):
continue

for record_label in records[nr].labels: # iterate all labels of the record (issue, or 1st PR)
if record_label in ch.labels and records[nr].pulls_count > 0:
if not records[nr].is_present_in_chapters:
Expand Down
11 changes: 6 additions & 5 deletions release_notes_generator/model/record.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from github.Repository import Repository
from github.Commit import Commit

from release_notes_generator.action_inputs import ActionInputs
from release_notes_generator.utils.constants import (
PR_STATE_CLOSED,
ISSUE_STATE_CLOSED,
Expand Down Expand Up @@ -264,21 +265,21 @@ def register_commit(self, commit: Commit) -> None:
logger.error("Commit %s not registered in any PR of record %s", commit.sha, self.number)

# TODO in Issue named 'Chapter line formatting - default'
def to_chapter_row(self, row_format="", increment_in_chapters=True) -> str:
def to_chapter_row(self, row_format="") -> str:
"""
Converts the record to a row in a chapter.
@param row_format: The format of the row.
@param increment_in_chapters: A boolean indicating whether to increment the count of chapters.
@return: The record as a row in a chapter.
"""
if increment_in_chapters:
self.increment_present_in_chapters()
self.increment_present_in_chapters()
row_prefix = f"{ActionInputs.get_duplicity_icon()} " if self.present_in_chapters() > 1 else ""

if self.__gh_issue is None:
p = self.__pulls[0]

row = f"PR: #{p.number} _{p.title}_"
row = f"{row_prefix}PR: #{p.number} _{p.title}_"

# Issue can have more authors (as multiple PRs can be present)
if self.authors is not None:
Expand All @@ -291,7 +292,7 @@ def to_chapter_row(self, row_format="", increment_in_chapters=True) -> str:
return f"{row}\n{self.get_rls_notes()}"

else:
row = f"#{self.__gh_issue.number} _{self.__gh_issue.title}_"
row = f"{row_prefix}#{self.__gh_issue.number} _{self.__gh_issue.title}_"

if self.authors is not None:
row = f"{row}, implemented by {self.authors}"
Expand Down
Loading

0 comments on commit d5751a9

Please sign in to comment.