Skip to content

Commit 3464930

Browse files
committed
Ensure PRs only show up once per changelog
1 parent a9d85f4 commit 3464930

File tree

3 files changed

+136
-43
lines changed

3 files changed

+136
-43
lines changed

docs/use.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,60 @@ You can choose to *remove* some types of PRs from your changelog by passing the
6464
left-most column above.
6565
```
6666

67+
### Pull Requests with Multiple Matching Labels
68+
69+
If a pull request has multiple labels that match different categories, it will appear in **only the first matching section** based on the order of categories processed. For example, a PR labeled with both `api-change` and `enhancement` will appear only in the "API and Breaking Changes" section, not in "Enhancements made".
70+
71+
The categories are processed in this order: `api_change`, `new`, `deprecate`, `enhancement`, `bug`, `maintenance`, `documentation`, `ci`. This ensures each PR appears exactly once in the changelog, preventing duplication across sections.
72+
73+
## Include Pull Request reviewers and commenters in your changelog
74+
75+
By default, GitHub Activity will include any _reviewer_ of a pull request in the item for that PR. This looks like the following:
76+
77+
## Include a list of all contributors at the end of your changelog
78+
79+
By default, this tool will include a long list of contributors at the end of your changelog. This is the unique set of all contributors that contributed to the release.
80+
81+
(how-does-this-tool-define-contributions-in-the-reports)=
82+
83+
### How we define contributors a changelog
84+
85+
GitHub Activity tries to automatically determine the unique list of contributors within a given window of time.
86+
There are many ways to define this, and there isn't necessarily a "correct" method out there.
87+
88+
We try to balance the two extremes of "anybody who shows up is recognized as contributing" and "nobody is recognized as contributing".
89+
We've chosen a few rules that try to reflect sustained engagement in issues/PRs, or contributions in the form of help in _others'_ issues or contributing code.
90+
91+
Here are the rules we follow for finding a list of contributors within a time window. A contributor is anyone who has:
92+
93+
- Contributed to a PR merged in that window (includes opening, merging, committing, commenting, or committing)
94+
- Commented on >= 2 issues that weren't theirs
95+
- Commented >= 6 times on any one issue
96+
- Known bot accounts are generally not considered contributors
97+
98+
We'd love feedback on whether this is a good set of rules to use.
99+
100+
## Strip PR type metadata from the changelog titles
101+
102+
If you follow the [title prefix convention used to split PRs](#prefixes-and-tags), you can remove these prefixes when you generate your changelog, so that they don't clutter the output.
103+
104+
To strip title prefix metadata, use the `--strip-brackets` flag.
105+
106+
For example, `[DOC] Add some documentation` will be rendered as `Add some documentation`.
107+
108+
## Change the heading level for your changelog items
109+
110+
To change the starting heading level for changelog items, use the `--heading-level N` flag. Where `N` is the starting heading level (e.g., `2` corresponds to `##`).
111+
112+
This is useful if you want to _embed_ your changelog into a larger one (e.g., `CHANGELOG.md`).
113+
114+
## Include issues in your changelog
115+
116+
To include closed issues in your changelog, use the `--include-issues` flag.
117+
118+
## Include opened issues in your changelog
119+
120+
To include issues and Pull Requests that were _opened_ in a time period, use teh `--include-opened` flag.
67121
(use:token)=
68122

69123
## Use a GitHub API token

github_activity/github_activity.py

Lines changed: 78 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import subprocess
77
import sys
88
import urllib
9+
from collections import OrderedDict
910
from pathlib import Path
1011
from subprocess import CalledProcessError
1112
from subprocess import PIPE
@@ -24,48 +25,74 @@
2425

2526

2627
# The tags and description to use in creating subsets of PRs
27-
TAGS_METADATA_BASE = {
28-
"api_change": {
29-
"tags": ["api-change", "apichange", "breaking"],
30-
"pre": ["BREAK", "BREAKING", "BRK", "UPGRADE"],
31-
"description": "API and Breaking Changes",
32-
},
33-
"new": {
34-
"tags": ["feature", "new"],
35-
"pre": ["NEW", "FEAT", "FEATURE"],
36-
"description": "New features added",
37-
},
38-
"enhancement": {
39-
"tags": ["enhancement", "enhancements"],
40-
"pre": ["ENH", "ENHANCEMENT", "IMPROVE", "IMP"],
41-
"description": "Enhancements made",
42-
},
43-
"bug": {
44-
"tags": ["bug", "bugfix", "bugs"],
45-
"pre": ["FIX", "BUG"],
46-
"description": "Bugs fixed",
47-
},
48-
"maintenance": {
49-
"tags": ["maintenance", "maint"],
50-
"pre": ["MAINT", "MNT"],
51-
"description": "Maintenance and upkeep improvements",
52-
},
53-
"documentation": {
54-
"tags": ["documentation", "docs", "doc"],
55-
"pre": ["DOC", "DOCS"],
56-
"description": "Documentation improvements",
57-
},
58-
"ci": {
59-
"tags": ["ci", "continuous-integration"],
60-
"pre": ["CI"],
61-
"description": "Continuous integration improvements",
62-
},
63-
"deprecate": {
64-
"tags": ["deprecation", "deprecate"],
65-
"pre": ["DEPRECATE", "DEPRECATION", "DEP"],
66-
"description": "Deprecated features",
67-
},
68-
}
28+
TAGS_METADATA_BASE = OrderedDict(
29+
[
30+
(
31+
"api_change",
32+
{
33+
"tags": ["api-change", "apichange", "breaking"],
34+
"pre": ["BREAK", "BREAKING", "BRK", "UPGRADE"],
35+
"description": "API and Breaking Changes",
36+
},
37+
),
38+
(
39+
"new",
40+
{
41+
"tags": ["feature", "new"],
42+
"pre": ["NEW", "FEAT", "FEATURE"],
43+
"description": "New features added",
44+
},
45+
),
46+
(
47+
"deprecate",
48+
{
49+
"tags": ["deprecation", "deprecate"],
50+
"pre": ["DEPRECATE", "DEPRECATION", "DEP"],
51+
"description": "Deprecated features",
52+
},
53+
),
54+
(
55+
"enhancement",
56+
{
57+
"tags": ["enhancement", "enhancements"],
58+
"pre": ["ENH", "ENHANCEMENT", "IMPROVE", "IMP"],
59+
"description": "Enhancements made",
60+
},
61+
),
62+
(
63+
"bug",
64+
{
65+
"tags": ["bug", "bugfix", "bugs"],
66+
"pre": ["FIX", "BUG"],
67+
"description": "Bugs fixed",
68+
},
69+
),
70+
(
71+
"maintenance",
72+
{
73+
"tags": ["maintenance", "maint"],
74+
"pre": ["MAINT", "MNT"],
75+
"description": "Maintenance and upkeep improvements",
76+
},
77+
),
78+
(
79+
"documentation",
80+
{
81+
"tags": ["documentation", "docs", "doc"],
82+
"pre": ["DOC", "DOCS"],
83+
"description": "Documentation improvements",
84+
},
85+
),
86+
(
87+
"ci",
88+
{
89+
"tags": ["ci", "continuous-integration"],
90+
"pre": ["CI"],
91+
"description": "Continuous integration improvements",
92+
},
93+
),
94+
]
95+
)
6996

7097
# exclude known bots from contributor lists
7198
# TODO: configurable? Everybody's got their own bots.
@@ -540,6 +567,9 @@ def generate_activity_md(
540567
)
541568

542569
# Separate out items by their tag types
570+
# Track which PRs have already been assigned to prevent duplicates
571+
assigned_prs = set()
572+
543573
for kind, kindmeta in tags_metadata.items():
544574
# First find the PRs based on tag
545575
mask = closed_prs["labels"].map(
@@ -551,9 +581,15 @@ def generate_activity_md(
551581
)
552582
mask = mask | mask_pre
553583

584+
# Exclude PRs that have already been assigned to a previous category
585+
mask = mask & ~closed_prs.index.isin(assigned_prs)
586+
554587
kindmeta["data"] = closed_prs.loc[mask]
555588
kindmeta["mask"] = mask
556589

590+
# Add the assigned PRs to our tracking set
591+
assigned_prs.update(closed_prs.loc[mask].index)
592+
557593
# All remaining PRs w/o a label go here
558594
all_masks = np.array(
559595
[~kindinfo["mask"].values for _, kindinfo in tags_metadata.items()]

tests/test_cli/test_pr_split.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
([full changelog](https://github.com/jupyter-book/jupyter-book/compare/v0.7.1...v0.7.3))
44

5+
## API and Breaking Changes
6+
7+
- 👌 IMPROVE: improving numbered sections [#826](https://github.com/jupyter-book/jupyter-book/pull/826) ([@choldgraf](https://github.com/choldgraf))
8+
59
## New features added
610

711
- ✨ NEW: Adding - chapter entries to _toc.yml [#817](https://github.com/jupyter-book/jupyter-book/pull/817) ([@choldgraf](https://github.com/choldgraf))
812

913
## Enhancements made
1014

11-
- 👌 IMPROVE: improving numbered sections [#826](https://github.com/jupyter-book/jupyter-book/pull/826) ([@choldgraf](https://github.com/choldgraf))
1215
- checking for toc modification time [#772](https://github.com/jupyter-book/jupyter-book/pull/772) ([@choldgraf](https://github.com/choldgraf), [@chrisjsewell](https://github.com/chrisjsewell))
1316
- first pass toc directive [#757](https://github.com/jupyter-book/jupyter-book/pull/757) ([@choldgraf](https://github.com/choldgraf), [@AakashGfude](https://github.com/AakashGfude))
1417

0 commit comments

Comments
 (0)