Skip to content

Commit d5751a9

Browse files
Feature/53 chapter line duplicity control custom and service chapters (#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.
1 parent dff934a commit d5751a9

16 files changed

+332
-24
lines changed

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- [Select start date for closed issues and PRs](#select-start-date-for-closed-issues-and-prs)
1515
- [Enable skipping of release notes for specific issues using label](#enable-skipping-of-release-notes-for-specific-issues-using-label)
1616
- [Enable Service Chapters](#enable-service-chapters)
17+
- [Showing Duplicity Lines In Chapters](#showing-duplicity-lines-in-chapters)
1718
- [Get Started](#get-started)
1819
- [Run Static Code Analysis](#running-static-code-analysis)
1920
- [Run Black Tool Locally](#run-black-tool-locally)
@@ -50,6 +51,16 @@ Generate Release Notes action is dedicated to enhance the quality and organizati
5051
- **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.
5152
- **Required**: Yes
5253

54+
### `duplicity-scope`
55+
- **Description**: Set to `custom` to allow duplicity issue lines to be shown only in custom chapters. Options: `custom`, `service`, `both`, `none`.
56+
- **Required**: No
57+
- **Default**: `both`
58+
59+
### `duplicity-icon`
60+
- **Description**: The icon used to indicate duplicity issue lines in the release notes. Icon will be placed at the beginning of the line.
61+
- **Required**: No
62+
- **Default**: `🔔`
63+
5364
### `published-at`
5465
- **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.
5566
- **Required**: No
@@ -86,7 +97,8 @@ Generate Release Notes action is dedicated to enhance the quality and organizati
8697

8798
## Outputs
8899
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.
89-
TODO - review
100+
101+
See the [example of output](./examples/output_example.md).
90102

91103
## Usage Example
92104

@@ -130,6 +142,8 @@ Add the following step to your GitHub workflow (in example are used non-default
130142
{"title": "New Features 🎉", "label": "feature"},
131143
{"title": "Bugfixes 🛠", "label": "bug"}
132144
]'
145+
duplicity-scope: 'service'
146+
duplicity-icon: '🔁'
133147
published-at: true
134148
skip-release-notes-label: 'ignore-in-release' # changing default value of label
135149
verbose: false
@@ -210,6 +224,17 @@ The action includes four specific warning chapters to highlight potential areas
210224
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.
211225

212226

227+
### Showing Duplicity Lines In Chapters
228+
By setting the `duplicity-scope` with one of the options, the action will show whether the duplicity issue lines are correct.
229+
- `custom`: will show duplicity lines only in custom chapters.
230+
- `service`: will show duplicity lines only in service chapters.
231+
- `both`: will show duplicity lines in both custom and service chapters.
232+
- `none`: will hide duplicity lines in all chapters.
233+
234+
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.
235+
236+
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.
237+
213238
## Get Started
214239

215240
Clone the repository and navigate to the project directory:

action.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ inputs:
2323
chapters:
2424
description: 'JSON string defining chapters and corresponding labels for categorization.'
2525
required: false
26+
duplicity-scope:
27+
description: 'Allow duplicity of issue lines in chapters. Scopes: custom, service, both, none.'
28+
required: false
29+
default: 'both'
30+
duplicity-icon:
31+
description: 'Icon to be used for duplicity warning. Icon is placed before the record line.'
32+
required: false
33+
default: '🔔'
2634
published-at:
2735
description: 'Use `published-at` timestamp instead of `created-at` as the reference point of previous Release.'
2836
required: false
@@ -91,6 +99,8 @@ runs:
9199
INPUT_GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }}
92100
INPUT_TAG_NAME: ${{ inputs.tag-name }}
93101
INPUT_CHAPTERS: ${{ inputs.chapters }}
102+
INPUT_DUPLICITY_SCOPE: ${{ inputs.duplicity-scope }}
103+
INPUT_DUPLICITY_ICON: ${{ inputs.duplicity-icon }}
94104
INPUT_WARNINGS: ${{ inputs.warnings }}
95105
INPUT_PUBLISHED_AT: ${{ inputs.published-at }}
96106
INPUT_SKIP_RELEASE_NOTES_LABEL: ${{ inputs.skip-release-notes-label }}

examples/output_example.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
### Breaking Changes 💥
2+
No entries detected.
3+
4+
### New Features 🎉
5+
- #22 _REQ: Submit Reviews_ in [#31](https://github.com/company/test-project/pull/31)
6+
- Now only book purchasers can submit reviews, with mandatory text and star ratings.
7+
- #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)
8+
- #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)
9+
10+
### Bugfixes 🛠
11+
- #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)
12+
- Another solved typos. Hello from second RLS notes comment.
13+
- Solved some typos.
14+
- PR: #41 _Initial commit._
15+
- Test release notes nr1
16+
- Test release notes nr2
17+
18+
### Closed Issues without Pull Request ⚠️
19+
- #3 _FEAT: User Authentication_
20+
- #4 _FEAT: Book Browsing_
21+
- #6 _FEAT: Shopping Cart_
22+
- #37 _Example Issue without PR_
23+
- #38 _Example Issue without Release notes comment_
24+
- #88 _Test issue_
25+
26+
### Closed Issues without User Defined Labels ⚠️
27+
- #1 _Initial version of project_ in [#2](https://github.com/company/test-project/pull/2)
28+
- #7 _REQ: User Login Functionality_ in [#13](https://github.com/company/test-project/pull/13)
29+
- #8 _REQ: User Registration Functionality_ in [#13](https://github.com/company/test-project/pull/13)
30+
- #9 _REQ: View Book List_ in [#14](https://github.com/company/test-project/pull/14)
31+
- #10 _REQ: Detailed Book Information_ in [#14](https://github.com/company/test-project/pull/14)
32+
- #11 _REQ: Adding Books to Shopping Cart_ in [#15](https://github.com/company/test-project/pull/15)
33+
- #12 _REQ: Viewing Shopping Cart Contents_ in [#15](https://github.com/company/test-project/pull/15)
34+
- #23 _REQ: View Reviews_ in [#27](https://github.com/company/test-project/pull/27)
35+
- #29 _Introduce workflow logic for Release notes_ in [#28](https://github.com/company/test-project/pull/28)
36+
- #30 _Introduce Release notes logic_ in [#32](https://github.com/company/test-project/pull/32)
37+
38+
### Merged PRs without Issue and User Defined Labels ⚠️
39+
- PR: #5 _BugFix - correct Issue GH folder location_
40+
- PR: #16 _repository improvement_
41+
- PR: #26 _Initial test headers_
42+
- PR: #39 _Initial commit._
43+
- PR: #40 _Initial commit._
44+
- PR: #42 _Initial commit._
45+
- PR: #43 _Feature/new tag_
46+
- PR: #45 _Initial commit._
47+
- PR: #46 _Revert "- Improved README.md (#36)"_
48+
- PR: #47 _- Added code for received tag format and correct version increase._
49+
- PR: #48 _Update of tag checks._
50+
- PR: #49 _Feature/tag checks update_
51+
- PR: #50 _Feature/tag checks update_
52+
- PR: #51 _Feature/tag checks update_
53+
- PR: #61 _New check implemented._
54+
- PR: #62 _Feature/add first tag check_
55+
- PR: #63 _New check implemented._
56+
- PR: #64 _Experiment with improving release worklflows._
57+
- PR: #66 _- Prepared workflow for RLS notes generation testing._
58+
59+
### Closed PRs without Issue and User Defined Labels ⚠️
60+
- PR: #60 _Test change to test close of PR instead of Merge._
61+
- PR: #65 _Fake change in PR to get PR._
62+
- PR: #92 _Fake change._
63+
64+
### Merged PRs Linked to 'Not Closed' Issue ⚠️
65+
- #20 _REQ: Search by Keywords_ in [#44](https://github.com/company/test-project/pull/44)
66+
- 🔔 #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)
67+
- Another solved typos. Hello from second RLS notes comment.
68+
- Solved some typos.
69+
- PR: #80 _Feature/multiline excludes_
70+
- #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)
71+
72+
### Others - No Topic ⚠️
73+
Previous filters caught all Issues or Pull Requests.
74+
75+
#### Full Changelog
76+
https://github.com/company/test-project/commits/v0.1.0

release_notes_generator/action_inputs.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@
3535
RUNNER_DEBUG,
3636
PRINT_EMPTY_CHAPTERS,
3737
CHAPTERS_TO_PR_WITHOUT_ISSUE,
38+
DUPLICITY_SCOPE,
39+
DUPLICITY_ICON,
3840
)
41+
from release_notes_generator.utils.enums import DuplicityScopeEnum
3942
from release_notes_generator.utils.gh_action import get_action_input
4043

4144
logger = logging.getLogger(__name__)
@@ -74,6 +77,26 @@ def get_chapters_json() -> str:
7477
"""
7578
return get_action_input(CHAPTERS)
7679

80+
@staticmethod
81+
def get_duplicity_scope() -> DuplicityScopeEnum:
82+
"""
83+
Get the duplicity scope parameter value from the action inputs.
84+
"""
85+
duplicity_scope = get_action_input(DUPLICITY_SCOPE, "both").upper()
86+
87+
try:
88+
return DuplicityScopeEnum(duplicity_scope)
89+
except ValueError:
90+
logger.error("Error: '%s' is not a valid DuplicityType.", duplicity_scope)
91+
return DuplicityScopeEnum.BOTH
92+
93+
@staticmethod
94+
def get_duplicity_icon() -> str:
95+
"""
96+
Get the duplicity icon from the action inputs.
97+
"""
98+
return get_action_input(DUPLICITY_ICON, "🔔")
99+
77100
@staticmethod
78101
def get_published_at() -> bool:
79102
"""
@@ -161,6 +184,10 @@ def validate_inputs():
161184
except json.JSONDecodeError:
162185
errors.append("Chapters JSON must be a valid JSON string.")
163186

187+
duplicity_icon = ActionInputs.get_duplicity_icon()
188+
if not isinstance(duplicity_icon, str) or not duplicity_icon.strip() or len(duplicity_icon) != 1:
189+
errors.append("Duplicity icon must be a non-empty string and have a length of 1.")
190+
164191
warnings = ActionInputs.get_warnings()
165192
ActionInputs.validate_input(warnings, bool, "Warnings must be a boolean.", errors)
166193

release_notes_generator/builder.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,19 @@ def build(self) -> str:
6161
@return: The release notes as a string.
6262
"""
6363
logger.info("Building Release Notes")
64-
user_defined_chapters = self.custom_chapters
65-
user_defined_chapters.populate(self.records)
66-
user_defined_chapters_str = user_defined_chapters.to_string()
64+
self.custom_chapters.populate(self.records)
65+
user_defined_chapters_str = self.custom_chapters.to_string()
6766

6867
user_defined_labels_nested = [
69-
user_defined_chapters.chapters[key].labels for key in user_defined_chapters.chapters
68+
self.custom_chapters.chapters[key].labels for key in self.custom_chapters.chapters
7069
]
7170
user_defined_labels = list(chain.from_iterable(user_defined_labels_nested))
7271

7372
if self.warnings:
7473
service_chapters = ServiceChapters(
7574
print_empty_chapters=self.print_empty_chapters,
7675
user_defined_labels=user_defined_labels,
77-
used_record_numbers=user_defined_chapters.populated_record_numbers,
76+
used_record_numbers=self.custom_chapters.populated_record_numbers,
7877
)
7978
service_chapters.populate(self.records)
8079

release_notes_generator/model/custom_chapters.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@
1515
#
1616

1717
"""
18-
This module contains the CustomChapters class which is responsible for representing the custom chapters in the release notes.
18+
This module contains the CustomChapters class which is responsible for representing the custom chapters in the release
19+
notes.
1920
"""
2021

2122
import json
2223

24+
from release_notes_generator.action_inputs import ActionInputs
2325
from release_notes_generator.model.base_chapters import BaseChapters
2426
from release_notes_generator.model.chapter import Chapter
2527
from release_notes_generator.model.record import Record
28+
from release_notes_generator.utils.enums import DuplicityScopeEnum
2629

2730

2831
class CustomChapters(BaseChapters):
@@ -39,6 +42,12 @@ def populate(self, records: dict[int, Record]) -> None:
3942
"""
4043
for nr in records: # iterate all records
4144
for ch in self.chapters.values(): # iterate all chapters
45+
if nr in self.populated_record_numbers_list and ActionInputs.get_duplicity_scope() not in (
46+
DuplicityScopeEnum.CUSTOM,
47+
DuplicityScopeEnum.BOTH,
48+
):
49+
continue
50+
4251
for record_label in records[nr].labels: # iterate all labels of the record (issue, or 1st PR)
4352
if record_label in ch.labels and records[nr].pulls_count > 0:
4453
if not records[nr].is_present_in_chapters:

release_notes_generator/model/record.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from github.Repository import Repository
2727
from github.Commit import Commit
2828

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

266267
# TODO in Issue named 'Chapter line formatting - default'
267-
def to_chapter_row(self, row_format="", increment_in_chapters=True) -> str:
268+
def to_chapter_row(self, row_format="") -> str:
268269
"""
269270
Converts the record to a row in a chapter.
270271
271272
@param row_format: The format of the row.
272273
@param increment_in_chapters: A boolean indicating whether to increment the count of chapters.
273274
@return: The record as a row in a chapter.
274275
"""
275-
if increment_in_chapters:
276-
self.increment_present_in_chapters()
276+
self.increment_present_in_chapters()
277+
row_prefix = f"{ActionInputs.get_duplicity_icon()} " if self.present_in_chapters() > 1 else ""
277278

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

281-
row = f"PR: #{p.number} _{p.title}_"
282+
row = f"{row_prefix}PR: #{p.number} _{p.title}_"
282283

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

293294
else:
294-
row = f"#{self.__gh_issue.number} _{self.__gh_issue.title}_"
295+
row = f"{row_prefix}#{self.__gh_issue.number} _{self.__gh_issue.title}_"
295296

296297
if self.authors is not None:
297298
row = f"{row}, implemented by {self.authors}"

0 commit comments

Comments
 (0)