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-after` entry to your category item, if the category has more than the defined `collapse-after` pull requests then it will show all pull requests collapsed for that category. Append the `collapse-after` integer to your category as following:

```yml
categories:
- title: '⬆️ Dependencies'
collapse-after: 3
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
48 changes: 37 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,42 @@ 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
}

// Add the category title to the changelog.
changeLog.push(
template(config['category-template'], { $TITLE: category.title }),
'\n\n'
)

// Define the pull requests into a single string.
const pullRequestString = pullRequestToString(category.pullRequests)

// Determine the collapse status.
const shouldCollapse =
category['collapse-after'] !== 0 &&
category.pullRequests.length > category['collapse-after']

// Add the pull requests to the changelog.
if (shouldCollapse) {
changeLog.push(
template(config['category-template'], { $TITLE: category.title }),
'<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')
} else {
changeLog.push(pullRequestString)
}
})

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

return changeLog.join('').trim()
}
Expand Down Expand Up @@ -129647,6 +129672,7 @@ const schema = (context) => {
Joi.object()
.keys({
title: Joi.string().required(),
'collapse-after': Joi.number().integer().min(0).default(0),
label: Joi.string(),
labels: Joi.array().items(Joi.string()).single().default([]),
})
Expand Down
47 changes: 36 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,42 @@ 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
}

// Add the category title to the changelog.
changeLog.push(
template(config['category-template'], { $TITLE: category.title }),
'\n\n'
)

// Define the pull requests into a single string.
const pullRequestString = pullRequestToString(category.pullRequests)

// Determine the collapse status.
const shouldCollapse =
category['collapse-after'] !== 0 &&
category.pullRequests.length > category['collapse-after']

// Add the pull requests to the changelog.
if (shouldCollapse) {
changeLog.push(
template(config['category-template'], { $TITLE: category.title }),
'<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')
} else {
changeLog.push(pullRequestString)
}
})

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-after': Joi.number().integer().min(0).default(0),
label: Joi.string(),
labels: Joi.array().items(Joi.string()).single().default([]),
})
Expand Down
5 changes: 5 additions & 0 deletions schema.json
Expand Up @@ -199,6 +199,11 @@
"title": {
"type": "string"
},
"collapse-after": {
"default": 0,
"type": "integer",
"minimum": 0
},
"label": {
"type": "string"
},
Expand Down
@@ -0,0 +1,18 @@
template: |
# What's Changed

$CHANGES

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

expect.assertions(1)
})

it('categorizes pull requests with a collapsed category', async () => {
getConfigMock('config-with-categories-with-collapse-after.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
46 changes: 46 additions & 0 deletions test/releases.test.js
Expand Up @@ -187,5 +187,51 @@ 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-after is set and more than 3 PRs', () => {
const config = {
...baseConfig,
categories: [{ title: 'Bugs', 'collapse-after': 3, 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-after is set and less than 3 PRs', () => {
const config = {
...baseConfig,
categories: [
{ title: 'Feature', 'collapse-after': 3, 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"
`)
})
})
})