diff --git a/README.md b/README.md
index 36ddef5ed..248e633f0 100644
--- a/README.md
+++ b/README.md
@@ -251,6 +251,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:
diff --git a/dist/index.js b/dist/index.js
index 991f017d6..2e3a31ed8 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -129297,8 +129297,8 @@ 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
@@ -129306,8 +129306,8 @@ const categorizePullRequests = (pullRequests, config) => {
if (labels.some((label) => category.labels.includes(label.name))) {
category.pullRequests.push(pullRequest)
}
- })
- })
+ }
+ }
return [uncategorizedPullRequests, categorizedPullRequests]
}
@@ -129356,17 +129356,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 }),
+ '',
+ '\n',
+ `${category.pullRequests.length} changes
`,
'\n\n',
- pullRequestToString(category.pullRequests)
+ pullRequestString,
+ '\n',
+ ' '
)
-
- 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()
}
@@ -129661,6 +129686,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([]),
})
diff --git a/lib/releases.js b/lib/releases.js
index cd58e9cb4..6cae5870b 100644
--- a/lib/releases.js
+++ b/lib/releases.js
@@ -182,8 +182,8 @@ 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
@@ -191,8 +191,8 @@ const categorizePullRequests = (pullRequests, config) => {
if (labels.some((label) => category.labels.includes(label.name))) {
category.pullRequests.push(pullRequest)
}
- })
- })
+ }
+ }
return [uncategorizedPullRequests, categorizedPullRequests]
}
@@ -241,17 +241,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 }),
+ '',
+ '\n',
+ `${category.pullRequests.length} changes
`,
'\n\n',
- pullRequestToString(category.pullRequests)
+ pullRequestString,
+ '\n',
+ ' '
)
-
- 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()
}
diff --git a/lib/schema.js b/lib/schema.js
index ef134681d..41a1e917e 100644
--- a/lib/schema.js
+++ b/lib/schema.js
@@ -115,6 +115,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([]),
})
diff --git a/schema.json b/schema.json
index 86d977dee..39a98b095 100644
--- a/schema.json
+++ b/schema.json
@@ -211,6 +211,11 @@
"title": {
"type": "string"
},
+ "collapse-after": {
+ "default": 0,
+ "type": "integer",
+ "minimum": 0
+ },
"label": {
"type": "string"
},
diff --git a/test/fixtures/config/config-with-categories-with-collapse-after.yml b/test/fixtures/config/config-with-categories-with-collapse-after.yml
new file mode 100644
index 000000000..bd4f4c114
--- /dev/null
+++ b/test/fixtures/config/config-with-categories-with-collapse-after.yml
@@ -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
diff --git a/test/index.test.js b/test/index.test.js
index 896f355e4..3057890d3 100644
--- a/test/index.test.js
+++ b/test/index.test.js
@@ -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!
+
+
+ 4 changes
+
+ * Add documentation (#5) @TimonVS
+ * Bug fixes (#3) @TimonVS
+ * Add big feature (#2) @TimonVS
+ * 👽 Add alien technology (#1) @TimonVS
+
+ ",
+ "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', () => {
diff --git a/test/releases.test.js b/test/releases.test.js
index 4353607ea..8dd8316fc 100644
--- a/test/releases.test.js
+++ b/test/releases.test.js
@@ -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
+
+
+ 5 changes
+
+ * A1 (#1) @ghost
+ * Adds missing (#3) @jetersen
+ * \`#code_block\` (#4) @jetersen
+ * Fixes #4 (#5) @Happypig375
+ * 2*2 should equal to 4*1 (#6) @jetersen
+ "
+ `)
+ })
+ 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 (#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"
+ `)
+ })
})
})