Skip to content
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

Add a collapse-after option for categories #1095

Merged
merged 14 commits into from Mar 7, 2022
10 changes: 10 additions & 0 deletions README.md
Expand Up @@ -249,6 +249,16 @@ Pull requests with the label "feature" or "fix" will now be grouped together:
Adding such labels to your PRs can be automated by using the embedded Autolabeler functionality (see below),
[PR Labeler](https://github.com/TimonVS/pr-labeler-action) or [Probot Auto Labeler](https://github.com/probot/autolabeler).

Optionally you can add a `collapse` boolean to your category item, if the category has more than 3 pull requests then it will show all pull requests collapsed for that category. Append the `collapse` boolean to your category as following:

```yml
categories:
- title: '⬆️ Dependencies'
collapse: true
labels:
- 'dependencies'
```

## Exclude Pull Requests

With the `exclude-labels` option you can exclude pull requests from the release notes using labels. For example, append the following to your `.github/release-drafter.yml` file:
Expand Down
42 changes: 31 additions & 11 deletions dist/index.js
Expand Up @@ -129288,17 +129288,17 @@ const categorizePullRequests = (pullRequests, config) => {
.filter(getFilterIncludedPullRequests(includeLabels))
.filter((pullRequest) => filterUncategorizedPullRequests(pullRequest))

categorizedPullRequests.map((category) => {
filteredPullRequests.map((pullRequest) => {
for (const category of categorizedPullRequests) {
for (const pullRequest of filteredPullRequests) {
// lets categorize some pull request based on labels
// note that having the same label in multiple categories
// then it is intended to "duplicate" the pull request into each category
const labels = pullRequest.labels.nodes
if (labels.some((label) => category.labels.includes(label.name))) {
category.pullRequests.push(pullRequest)
}
})
})
}
}

return [uncategorizedPullRequests, categorizedPullRequests]
}
Expand Down Expand Up @@ -129347,17 +129347,36 @@ const generateChangeLog = (mergedPullRequests, config) => {
changeLog.push(pullRequestToString(uncategorizedPullRequests), '\n\n')
}

categorizedPullRequests.map((category, index) => {
if (category.pullRequests.length > 0) {
for (const [index, category] of categorizedPullRequests.entries()) {
if (category.pullRequests.length === 0) {
continue
}
const categoryTitle = template(config['category-template'], {
$TITLE: category.title,
})
const pullRequestString = pullRequestToString(category.pullRequests)

if (
!category.collapse ||
(category.collapse && category.pullRequests.length < 4)
) {
changeLog.push(categoryTitle, '\n\n', pullRequestString)
} else {
changeLog.push(
template(config['category-template'], { $TITLE: category.title }),
categoryTitle,
'\n',
'<details>',
'\n',
`<summary>${category.pullRequests.length} changes</summary>`,
'\n\n',
pullRequestToString(category.pullRequests)
pullRequestString,
'\n',
'</details>'
)

if (index + 1 !== categorizedPullRequests.length) changeLog.push('\n\n')
}
})

if (index + 1 !== categorizedPullRequests.length) changeLog.push('\n\n')
}

return changeLog.join('').trim()
}
Expand Down Expand Up @@ -129647,6 +129666,7 @@ const schema = (context) => {
Joi.object()
.keys({
title: Joi.string().required(),
collapse: Joi.boolean().default(false),
label: Joi.string(),
labels: Joi.array().items(Joi.string()).single().default([]),
})
Expand Down
41 changes: 30 additions & 11 deletions lib/releases.js
Expand Up @@ -178,17 +178,17 @@ const categorizePullRequests = (pullRequests, config) => {
.filter(getFilterIncludedPullRequests(includeLabels))
.filter((pullRequest) => filterUncategorizedPullRequests(pullRequest))

categorizedPullRequests.map((category) => {
filteredPullRequests.map((pullRequest) => {
for (const category of categorizedPullRequests) {
for (const pullRequest of filteredPullRequests) {
// lets categorize some pull request based on labels
// note that having the same label in multiple categories
// then it is intended to "duplicate" the pull request into each category
const labels = pullRequest.labels.nodes
if (labels.some((label) => category.labels.includes(label.name))) {
category.pullRequests.push(pullRequest)
}
})
})
}
}

return [uncategorizedPullRequests, categorizedPullRequests]
}
Expand Down Expand Up @@ -237,17 +237,36 @@ const generateChangeLog = (mergedPullRequests, config) => {
changeLog.push(pullRequestToString(uncategorizedPullRequests), '\n\n')
}

categorizedPullRequests.map((category, index) => {
if (category.pullRequests.length > 0) {
for (const [index, category] of categorizedPullRequests.entries()) {
if (category.pullRequests.length === 0) {
continue
}
const categoryTitle = template(config['category-template'], {
$TITLE: category.title,
})
const pullRequestString = pullRequestToString(category.pullRequests)

if (
!category.collapse ||
(category.collapse && category.pullRequests.length < 4)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you think this needs to be configurable, feel free to add it :)

Please follow the current config naming with word-another-word

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could, but I have no idea what to name it 🙈 Any suggestions?

Copy link
Member

@jetersen jetersen Mar 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

collapse-at is fine it will go together with collapse. The readme would have to document whether it is greater than or less than that is used.
The default may be greater than 3?

Potentially could move the condition to outside the if statement.

So the if statement might say if (shouldCollapse) or if (shouldNotCollapse)

) {
changeLog.push(categoryTitle, '\n\n', pullRequestString)
} else {
changeLog.push(
template(config['category-template'], { $TITLE: category.title }),
categoryTitle,
'\n',
robbinjanssen marked this conversation as resolved.
Show resolved Hide resolved
'<details>',
'\n',
`<summary>${category.pullRequests.length} changes</summary>`,
'\n\n',
robbinjanssen marked this conversation as resolved.
Show resolved Hide resolved
pullRequestToString(category.pullRequests)
pullRequestString,
'\n',
'</details>'
)

if (index + 1 !== categorizedPullRequests.length) changeLog.push('\n\n')
}
})

if (index + 1 !== categorizedPullRequests.length) changeLog.push('\n\n')
}

return changeLog.join('').trim()
}
Expand Down
1 change: 1 addition & 0 deletions lib/schema.js
Expand Up @@ -111,6 +111,7 @@ const schema = (context) => {
Joi.object()
.keys({
title: Joi.string().required(),
collapse: Joi.boolean().default(false),
label: Joi.string(),
labels: Joi.array().items(Joi.string()).single().default([]),
})
Expand Down
4 changes: 4 additions & 0 deletions schema.json
Expand Up @@ -199,6 +199,10 @@
"title": {
"type": "string"
},
"collapse": {
"default": false,
"type": "boolean"
},
"label": {
"type": "string"
},
Expand Down
18 changes: 18 additions & 0 deletions test/fixtures/config/config-with-categories-with-collapse.yml
@@ -0,0 +1,18 @@
template: |
# What's Changed

$CHANGES

categories:
- title: 🚀 All the things!
collapse: true
labels:
- feature
- enhancement
- fix
- bugfix
- bug
- sentry
- skip-changelog
- title: 👻 Maintenance
label: chore
54 changes: 54 additions & 0 deletions test/index.test.js
Expand Up @@ -1198,6 +1198,60 @@ describe('release-drafter', () => {

expect.assertions(1)
})

it('categorizes pull requests with a collapsed category', async () => {
getConfigMock('config-with-categories-with-collapse.yml')

nock('https://api.github.com')
.get('/repos/toolmantim/release-drafter-test-project/releases')
.query(true)
.reply(200, [releasePayload])

nock('https://api.github.com')
.post('/graphql', (body) =>
body.query.includes('query findCommitsWithAssociatedPullRequests')
)
.reply(200, graphqlCommitsMergeCommit)

nock('https://api.github.com')
.post(
'/repos/toolmantim/release-drafter-test-project/releases',
(body) => {
expect(body).toMatchInlineSnapshot(`
Object {
"body": "# What's Changed

* Update dependencies (#4) @TimonVS

## 🚀 All the things!
<details>
<summary>4 changes</summary>

* Add documentation (#5) @TimonVS
* Bug fixes (#3) @TimonVS
* Add big feature (#2) @TimonVS
* 👽 Add alien technology (#1) @TimonVS
</details>
",
"draft": true,
"name": "",
"prerelease": false,
"tag_name": "",
"target_commitish": "refs/heads/master",
}
`)
return true
}
)
.reply(200, releasePayload)

await probot.receive({
name: 'push',
payload: pushPayload,
})

expect.assertions(1)
})
})

describe('with exclude-labels config', () => {
Expand Down
43 changes: 43 additions & 0 deletions test/releases.test.js
Expand Up @@ -187,5 +187,48 @@ describe('releases', () => {
* Adds @<!---->nullable annotations to the 1\\\\*1+2\\\\*4 test in \\\\\`tests.java\\\\\` (#0) @Happypig375"
`)
})
it('adds proper details/summary markdown when collapse is set to true and more than 3 PRs', () => {
const config = {
...baseConfig,
categories: [{ title: 'Bugs', collapse: true, labels: 'bug' }],
}
const changelog = generateChangeLog(pullRequests, config)
expect(changelog).toMatchInlineSnapshot(`
"* B2 (#2) @ghost
* Rename __confgs\\\\confg.yml to __configs\\\\config.yml (#7) @ghost
* Adds @nullable annotations to the 1*1+2*4 test in \`tests.java\` (#0) @Happypig375

## Bugs
<details>
<summary>5 changes</summary>

* A1 (#1) @ghost
* Adds missing <example> (#3) @jetersen
* \`#code_block\` (#4) @jetersen
* Fixes #4 (#5) @Happypig375
* 2*2 should equal to 4*1 (#6) @jetersen
</details>"
`)
})
it('does not add proper details/summary markdown when collapse is set to true and less than 3 PRs', () => {
const config = {
...baseConfig,
categories: [{ title: 'Feature', collapse: true, labels: 'feature' }],
}
const changelog = generateChangeLog(pullRequests, config)
expect(changelog).toMatchInlineSnapshot(`
"* A1 (#1) @ghost
* Adds missing <example> (#3) @jetersen
* \`#code_block\` (#4) @jetersen
* Fixes #4 (#5) @Happypig375
* 2*2 should equal to 4*1 (#6) @jetersen
* Rename __confgs\\\\confg.yml to __configs\\\\config.yml (#7) @ghost

## Feature

* B2 (#2) @ghost
* Adds @nullable annotations to the 1*1+2*4 test in \`tests.java\` (#0) @Happypig375"
`)
})
})
})