From 3cbe8cc47d031aba9e5f1343d8afafbb8df4f5ae Mon Sep 17 00:00:00 2001 From: Robbin Janssen Date: Mon, 7 Mar 2022 19:35:20 +0100 Subject: [PATCH] Add a `collapse-after` option for categories (#1095) Co-authored-by: Joseph Petersen --- README.md | 10 ++++ dist/index.js | 48 ++++++++++++---- lib/releases.js | 47 ++++++++++++---- lib/schema.js | 1 + schema.json | 5 ++ ...ig-with-categories-with-collapse-after.yml | 18 ++++++ test/index.test.js | 55 +++++++++++++++++++ test/releases.test.js | 46 ++++++++++++++++ 8 files changed, 208 insertions(+), 22 deletions(-) create mode 100644 test/fixtures/config/config-with-categories-with-collapse-after.yml 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" + `) + }) }) })