Merge pull request #726 from mikepenz/feature/725
Introduce new API to include open PRs within the generated changelog
This commit is contained in:
@@ -83,8 +83,9 @@ A full set list of possible output values for this action.
|
|||||||
| `outputs.toTag` | Defines the `toTag` which describes the upper bound to process pull request for |
|
| `outputs.toTag` | Defines the `toTag` which describes the upper bound to process pull request for |
|
||||||
| `outputs.failed` | Defines if there was an issue with the action run, and the changelog may not have been generated correctly. [true, false] |
|
| `outputs.failed` | Defines if there was an issue with the action run, and the changelog may not have been generated correctly. [true, false] |
|
||||||
| `outputs.pull_requests` | Defines a `,` joined array with all PR IDs associated with the generated changelog. |
|
| `outputs.pull_requests` | Defines a `,` joined array with all PR IDs associated with the generated changelog. |
|
||||||
| `outputs.categorized_prs` | Count of PRs which were successfully categorized as part of the action. |
|
| `outputs.categorized_prs` | Count of PRs which were successfully categorized as part of the action. |
|
||||||
| `outputs.uncategorized_prs` | Count of PRs which were not categorized as part of the action. |
|
| `outputs.open_prs` | Count of open PRs. Only fetched if `includeOpen` is enabled. |
|
||||||
|
| `outputs.uncategorized_prs` | Count of PRs which were not categorized as part of the action. |
|
||||||
|
|
||||||
|
|
||||||
## Full Sample 🖥️
|
## Full Sample 🖥️
|
||||||
@@ -263,7 +264,8 @@ For advanced use cases additional settings can be provided to the action
|
|||||||
| `toTag` | Defines until which tag the changelog will consider merged pull requests |
|
| `toTag` | Defines until which tag the changelog will consider merged pull requests |
|
||||||
| `path` | Allows to specify an alternative sub directory, to use as base |
|
| `path` | Allows to specify an alternative sub directory, to use as base |
|
||||||
| `token` | Alternative config to specify token. You should prefer `env.GITHUB_TOKEN` instead though |
|
| `token` | Alternative config to specify token. You should prefer `env.GITHUB_TOKEN` instead though |
|
||||||
| `baseUrl` | Alternative config to specify base url for GitHub Enterprise authentication. Default value set to `https://api.github.com` |
|
| `baseUrl` | Alternative config to specify base url for GitHub Enterprise authentication. Default value set to `https://api.github.com` |
|
||||||
|
| `includeOpen` | Enables to also fetch currently open PRs. Default: false |
|
||||||
| `ignorePreReleases` | Allows to ignore pre-releases for changelog generation (E.g. for 1.0.1... 1.0.0-rc02 <- ignore, 1.0.0 <- pick). Only used if `fromTag` was not specified. Default: false |
|
| `ignorePreReleases` | Allows to ignore pre-releases for changelog generation (E.g. for 1.0.1... 1.0.0-rc02 <- ignore, 1.0.0 <- pick). Only used if `fromTag` was not specified. Default: false |
|
||||||
| `failOnError` | Defines if the action will result in a build failure if problems occurred. Default: false |
|
| `failOnError` | Defines if the action will result in a build failure if problems occurred. Default: false |
|
||||||
| `commitMode` | Special configuration for projects which work without PRs. Uses commit messages as changelog. This mode looses access to information only available for PRs. Default: false |
|
| `commitMode` | Special configuration for projects which work without PRs. Uses commit messages as changelog. This mode looses access to information only available for PRs. Default: false |
|
||||||
@@ -274,19 +276,21 @@ For advanced use cases additional settings can be provided to the action
|
|||||||
|
|
||||||
Table of supported placeholders allowed to be used in the `pr_template` configuration, which will be included in the release notes / changelog.
|
Table of supported placeholders allowed to be used in the `pr_template` configuration, which will be included in the release notes / changelog.
|
||||||
|
|
||||||
| **Placeholder** | **Description** |
|
| **Placeholder** | **Description** |
|
||||||
|------------------|-------------------------------------------------------------|
|
|-------------------|-------------------------------------------------------------|
|
||||||
| `${{NUMBER}}` | The number referencing this pull request. E.g. 13 |
|
| `${{NUMBER}}` | The number referencing this pull request. E.g. 13 |
|
||||||
| `${{TITLE}}` | Specified title of the merged pull request |
|
| `${{TITLE}}` | Specified title of the merged pull request |
|
||||||
| `${{URL}}` | Url linking to the pull request on GitHub |
|
| `${{URL}}` | Url linking to the pull request on GitHub |
|
||||||
| `${{MERGED_AT}}` | The ISO time, the pull request was merged at |
|
| `${{STATUS}}` | Status of the PR. Usually always `merged`. Possibly `Open` if `includeOpen` is configured. |
|
||||||
| `${{MERGE_SHA}}` | The commit SHA, the pull request was merged with |
|
| `${{CREATED_AT}}` | The ISO time, the pull request was created at |
|
||||||
| `${{AUTHOR}}` | Author creating and opening the pull request |
|
| `${{MERGED_AT}}` | The ISO time, the pull request was merged at |
|
||||||
| `${{LABELS}}` | The labels associated with this pull request, joined by `,` |
|
| `${{MERGE_SHA}}` | The commit SHA, the pull request was merged with |
|
||||||
| `${{MILESTONE}}` | Milestone this PR was part of, as assigned on GitHub |
|
| `${{AUTHOR}}` | Author creating and opening the pull request |
|
||||||
| `${{BODY}}` | Description/Body of the pull request as specified on GitHub |
|
| `${{LABELS}}` | The labels associated with this pull request, joined by `,` |
|
||||||
| `${{ASSIGNEES}}` | Login names of assigned GitHub users, joined by `,` |
|
| `${{MILESTONE}}` | Milestone this PR was part of, as assigned on GitHub |
|
||||||
| `${{REVIEWERS}}` | GitHub Login names of specified reviewers, joined by `,` |
|
| `${{BODY}}` | Description/Body of the pull request as specified on GitHub |
|
||||||
|
| `${{ASSIGNEES}}` | Login names of assigned GitHub users, joined by `,` |
|
||||||
|
| `${{REVIEWERS}}` | GitHub Login names of specified reviewers, joined by `,` |
|
||||||
|
|
||||||
### Template placeholders
|
### Template placeholders
|
||||||
|
|
||||||
@@ -296,6 +300,7 @@ Table of supported placeholders allowed to be used in the `template` and `empty_
|
|||||||
|----------------------------|----------------------------------------------------------------------------------------------------|:---------:|
|
|----------------------------|----------------------------------------------------------------------------------------------------|:---------:|
|
||||||
| `${{CHANGELOG}}` | The contents of the changelog, matching the labels as specified in the categories configuration | |
|
| `${{CHANGELOG}}` | The contents of the changelog, matching the labels as specified in the categories configuration | |
|
||||||
| `${{UNCATEGORIZED}}` | All pull requests not matching a specified label in categories | |
|
| `${{UNCATEGORIZED}}` | All pull requests not matching a specified label in categories | |
|
||||||
|
| `${{OPEN}}` | All open pull requests. Will only be fetched if `includeOpen` is enabled. | |
|
||||||
| `${{IGNORED}}` | All pull requests defining labels matching the `ignore_labels` configuration | |
|
| `${{IGNORED}}` | All pull requests defining labels matching the `ignore_labels` configuration | |
|
||||||
| `${{OWNER}}` | Describes the owner of the repository the changelog was generated for | x |
|
| `${{OWNER}}` | Describes the owner of the repository the changelog was generated for | x |
|
||||||
| `${{REPO}}` | The repository name of the repo the changelog was generated for | x |
|
| `${{REPO}}` | The repository name of the repo the changelog was generated for | x |
|
||||||
@@ -304,6 +309,7 @@ Table of supported placeholders allowed to be used in the `template` and `empty_
|
|||||||
| `${{RELEASE_DIFF}}` | Introduces a link to the full diff between from tag and to tag releases | x |
|
| `${{RELEASE_DIFF}}` | Introduces a link to the full diff between from tag and to tag releases | x |
|
||||||
| `${{CATEGORIZED_COUNT}}` | The count of PRs which were categorized | |
|
| `${{CATEGORIZED_COUNT}}` | The count of PRs which were categorized | |
|
||||||
| `${{UNCATEGORIZED_COUNT}}` | The count of PRs and changes which were not categorized. No label overlapping with category labels | |
|
| `${{UNCATEGORIZED_COUNT}}` | The count of PRs and changes which were not categorized. No label overlapping with category labels | |
|
||||||
|
| `${{OPEN_COUNT}}` | The count of open PRs. Will only be fetched if `includeOpen` is configured. | |
|
||||||
| `${{IGNORED_COUNT}}` | The count of PRs and changes which were specifically ignored from the changelog. | |
|
| `${{IGNORED_COUNT}}` | The count of PRs and changes which were specifically ignored from the changelog. | |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ it('Should have empty changelog (tags)', async () => {
|
|||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: 'v0.0.1',
|
fromTag: 'v0.0.1',
|
||||||
toTag: 'v0.0.2',
|
toTag: 'v0.0.2',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -33,6 +34,7 @@ it('Should match generated changelog (tags)', async () => {
|
|||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: 'v0.0.1',
|
fromTag: 'v0.0.1',
|
||||||
toTag: 'v0.0.3',
|
toTag: 'v0.0.3',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -58,6 +60,7 @@ it('Should match generated changelog (refs)', async () => {
|
|||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3',
|
fromTag: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3',
|
||||||
toTag: 'fa3788c8c4b3373ef8424ce3eb008a5cd07cc5aa',
|
toTag: 'fa3788c8c4b3373ef8424ce3eb008a5cd07cc5aa',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -91,6 +94,7 @@ it('Should match generated changelog and replace all occurrences (refs)', async
|
|||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3',
|
fromTag: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3',
|
||||||
toTag: 'fa3788c8c4b3373ef8424ce3eb008a5cd07cc5aa',
|
toTag: 'fa3788c8c4b3373ef8424ce3eb008a5cd07cc5aa',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -126,6 +130,7 @@ it('Should match ordered ASC', async () => {
|
|||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: 'v0.3.0',
|
fromTag: 'v0.3.0',
|
||||||
toTag: 'v0.5.0',
|
toTag: 'v0.5.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -148,6 +153,7 @@ it('Should match ordered DESC', async () => {
|
|||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: 'v0.3.0',
|
fromTag: 'v0.3.0',
|
||||||
toTag: 'v0.5.0',
|
toTag: 'v0.5.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -170,6 +176,7 @@ it('Should ignore PRs not merged into develop branch', async () => {
|
|||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: 'v1.3.1',
|
fromTag: 'v1.3.1',
|
||||||
toTag: 'v1.4.0',
|
toTag: 'v1.4.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -190,6 +197,7 @@ it('Should ignore PRs not merged into main branch', async () => {
|
|||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: 'v1.3.1',
|
fromTag: 'v1.3.1',
|
||||||
toTag: 'v1.4.0',
|
toTag: 'v1.4.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ it('Should match generated changelog (unspecified fromTag)', async () => {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@ it('Should match generated changelog (unspecified tags)', async () => {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -65,6 +67,7 @@ it('Should use empty placeholder', async () => {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -89,6 +92,7 @@ it('Should fill empty placeholders', async () => {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -115,6 +119,7 @@ it('Should fill `template` placeholders', async () => {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -141,6 +146,7 @@ it('Should fill `template` placeholders, ignore', async () => {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -167,6 +173,7 @@ it('Uncategorized category', async () => {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -192,6 +199,7 @@ it('Verify commit based changelog', async () => {
|
|||||||
'v0.0.3',
|
'v0.0.3',
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
true,
|
true,
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
@@ -218,6 +226,7 @@ it('Verify commit based changelog, with emoji categorisation', async () => {
|
|||||||
'17a9e4dfaedcabe6a6eff2754bebb715e1c58ec4',
|
'17a9e4dfaedcabe6a6eff2754bebb715e1c58ec4',
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
true,
|
true,
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
@@ -228,3 +237,57 @@ it('Verify commit based changelog, with emoji categorisation', async () => {
|
|||||||
`## 🚀 Features\n\n- add dynamic merging\n- add auto-cleaning\n- add built-in adb support\n- add adb fallback (thanks to @mikepenz ;))\n- add install note\n- add @mikepenz to credits\n\n## 🐛 Fixes\n\n- fix dynamic lib replacement\n- fix apostrophe issue with app name\n- fix java.util.logger error\n\n## 💬 Other\n\n- update screenshot with truecaller stack\n\n`
|
`## 🚀 Features\n\n- add dynamic merging\n- add auto-cleaning\n- add built-in adb support\n- add adb fallback (thanks to @mikepenz ;))\n- add install note\n- add @mikepenz to credits\n\n## 🐛 Fixes\n\n- fix dynamic lib replacement\n- fix apostrophe issue with app name\n- fix java.util.logger error\n\n## 💬 Other\n\n- update screenshot with truecaller stack\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Verify default inclusion of open PRs', async () => {
|
||||||
|
const configuration = resolveConfiguration(
|
||||||
|
'',
|
||||||
|
'configs_test/configuration_including_open.json'
|
||||||
|
)
|
||||||
|
const releaseNotesBuilder = new ReleaseNotesBuilder(
|
||||||
|
null, // baseUrl
|
||||||
|
null, // token
|
||||||
|
'.', // repoPath
|
||||||
|
'mikepenz', // user
|
||||||
|
'release-changelog-builder-action-playground', // repo
|
||||||
|
'1.5.0', // fromTag
|
||||||
|
'2.0.0', // toTag
|
||||||
|
true, // includeOpen
|
||||||
|
false, // failOnError
|
||||||
|
false, // ignorePrePrelease
|
||||||
|
false, // commitMode
|
||||||
|
configuration // configuration
|
||||||
|
)
|
||||||
|
|
||||||
|
const changeLog = await releaseNotesBuilder.build()
|
||||||
|
console.log(changeLog)
|
||||||
|
expect(changeLog).toStrictEqual(
|
||||||
|
`## 🚀 Features\n\n- A feature to be going to v2 (nr3) (#3) merged\n- New feature to keep open (nr5) (#7) open\n\n\n\n\nUncategorized\n\n\n\nOpen\n- New feature to keep open (nr5) (#7) open\n`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Verify custom categorisation of open PRs', async () => {
|
||||||
|
const configuration = resolveConfiguration(
|
||||||
|
'',
|
||||||
|
'configs_test/configuration_excluding_open.json'
|
||||||
|
)
|
||||||
|
const releaseNotesBuilder = new ReleaseNotesBuilder(
|
||||||
|
null, // baseUrl
|
||||||
|
null, // token
|
||||||
|
'.', // repoPath
|
||||||
|
'mikepenz', // user
|
||||||
|
'release-changelog-builder-action-playground', // repo
|
||||||
|
'1.5.0', // fromTag
|
||||||
|
'2.0.0', // toTag
|
||||||
|
true, // includeOpen
|
||||||
|
false, // failOnError
|
||||||
|
false, // ignorePrePrelease
|
||||||
|
false, // commitMode
|
||||||
|
configuration // configuration
|
||||||
|
)
|
||||||
|
|
||||||
|
const changeLog = await releaseNotesBuilder.build()
|
||||||
|
console.log(changeLog)
|
||||||
|
expect(changeLog).toStrictEqual(
|
||||||
|
`## 🚀 Features Merged\n\n- A feature to be going to v2 (nr3) -- (#3) [merged] {feature}\n\n## 🚀 Features Open\n\n- New feature to keep open (nr5) -- (#7) [open] {feature}\n\n`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ mergedPullRequests.push(
|
|||||||
title: '[Feature][AB-1234] - this is a PR 1 title message',
|
title: '[Feature][AB-1234] - this is a PR 1 title message',
|
||||||
htmlURL: '',
|
htmlURL: '',
|
||||||
baseBranch: '',
|
baseBranch: '',
|
||||||
|
createdAt: moment(),
|
||||||
mergedAt: moment(),
|
mergedAt: moment(),
|
||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
@@ -41,13 +42,15 @@ mergedPullRequests.push(
|
|||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body for this matter',
|
body: 'no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
requestedReviewers: []
|
requestedReviewers: [],
|
||||||
|
status: "merged"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
number: 2,
|
number: 2,
|
||||||
title: '[Issue][AB-4321] - this is a PR 2 title message',
|
title: '[Issue][AB-4321] - this is a PR 2 title message',
|
||||||
htmlURL: '',
|
htmlURL: '',
|
||||||
baseBranch: '',
|
baseBranch: '',
|
||||||
|
createdAt: moment(),
|
||||||
mergedAt: moment(),
|
mergedAt: moment(),
|
||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
@@ -56,13 +59,15 @@ mergedPullRequests.push(
|
|||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body for this matter',
|
body: 'no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
requestedReviewers: []
|
requestedReviewers: [],
|
||||||
|
status: "merged"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
number: 3,
|
number: 3,
|
||||||
title: '[Issue][Feature][AB-1234321] - this is a PR 3 title message',
|
title: '[Issue][Feature][AB-1234321] - this is a PR 3 title message',
|
||||||
htmlURL: '',
|
htmlURL: '',
|
||||||
baseBranch: '',
|
baseBranch: '',
|
||||||
|
createdAt: moment(),
|
||||||
mergedAt: moment(),
|
mergedAt: moment(),
|
||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
@@ -71,13 +76,15 @@ mergedPullRequests.push(
|
|||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body for this matter',
|
body: 'no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
requestedReviewers: []
|
requestedReviewers: [],
|
||||||
|
status: "merged"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
number: 4,
|
number: 4,
|
||||||
title: '[AB-404] - not found label',
|
title: '[AB-404] - not found label',
|
||||||
htmlURL: '',
|
htmlURL: '',
|
||||||
baseBranch: '',
|
baseBranch: '',
|
||||||
|
createdAt: moment(),
|
||||||
mergedAt: moment(),
|
mergedAt: moment(),
|
||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
@@ -86,7 +93,8 @@ mergedPullRequests.push(
|
|||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body for this matter',
|
body: 'no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
requestedReviewers: []
|
requestedReviewers: [],
|
||||||
|
status: "merged"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -95,6 +103,7 @@ const pullRequestWithLabelInBody: PullRequestInfo = {
|
|||||||
title: 'label in body',
|
title: 'label in body',
|
||||||
htmlURL: '',
|
htmlURL: '',
|
||||||
baseBranch: '',
|
baseBranch: '',
|
||||||
|
createdAt: moment(),
|
||||||
mergedAt: moment(),
|
mergedAt: moment(),
|
||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
@@ -103,7 +112,8 @@ const pullRequestWithLabelInBody: PullRequestInfo = {
|
|||||||
milestone: '',
|
milestone: '',
|
||||||
body: '[Issue][Feature][AB-1234321] - no magic body for this matter',
|
body: '[Issue][Feature][AB-1234321] - no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
requestedReviewers: []
|
requestedReviewers: [],
|
||||||
|
status: "merged"
|
||||||
}
|
}
|
||||||
|
|
||||||
it('Extract label from title, combined regex', async () => {
|
it('Extract label from title, combined regex', async () => {
|
||||||
@@ -120,6 +130,7 @@ it('Extract label from title, combined regex', async () => {
|
|||||||
repo: 'test-repo',
|
repo: 'test-repo',
|
||||||
fromTag: '1.0.0',
|
fromTag: '1.0.0',
|
||||||
toTag: '2.0.0',
|
toTag: '2.0.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -147,6 +158,7 @@ it('Extract label from title and body, combined regex', async () => {
|
|||||||
repo: 'test-repo',
|
repo: 'test-repo',
|
||||||
fromTag: '1.0.0',
|
fromTag: '1.0.0',
|
||||||
toTag: '2.0.0',
|
toTag: '2.0.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -176,6 +188,7 @@ it('Extract label from title, split regex', async () => {
|
|||||||
repo: 'test-repo',
|
repo: 'test-repo',
|
||||||
fromTag: '1.0.0',
|
fromTag: '1.0.0',
|
||||||
toTag: '2.0.0',
|
toTag: '2.0.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -205,6 +218,7 @@ it('Extract label from title, match', async () => {
|
|||||||
repo: 'test-repo',
|
repo: 'test-repo',
|
||||||
fromTag: '1.0.0',
|
fromTag: '1.0.0',
|
||||||
toTag: '2.0.0',
|
toTag: '2.0.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -229,6 +243,7 @@ it('Extract label from title, match multiple', async () => {
|
|||||||
repo: 'test-repo',
|
repo: 'test-repo',
|
||||||
fromTag: '1.0.0',
|
fromTag: '1.0.0',
|
||||||
toTag: '2.0.0',
|
toTag: '2.0.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -254,6 +269,7 @@ it('Extract label from title, match multiple, custon non matching label', async
|
|||||||
repo: 'test-repo',
|
repo: 'test-repo',
|
||||||
fromTag: '1.0.0',
|
fromTag: '1.0.0',
|
||||||
toTag: '2.0.0',
|
toTag: '2.0.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
@@ -272,6 +288,7 @@ pullRequestsWithLabels.push(
|
|||||||
title: '[ABC-1234] - this is a PR 1 title message',
|
title: '[ABC-1234] - this is a PR 1 title message',
|
||||||
htmlURL: '',
|
htmlURL: '',
|
||||||
baseBranch: '',
|
baseBranch: '',
|
||||||
|
createdAt: moment(),
|
||||||
mergedAt: moment(),
|
mergedAt: moment(),
|
||||||
mergeCommitSha: 'sha1-1',
|
mergeCommitSha: 'sha1-1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
@@ -280,13 +297,15 @@ pullRequestsWithLabels.push(
|
|||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body for this matter',
|
body: 'no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
requestedReviewers: []
|
requestedReviewers: [],
|
||||||
|
status: "merged"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
number: 2,
|
number: 2,
|
||||||
title: '[ABC-4321] - this is a PR 2 title message',
|
title: '[ABC-4321] - this is a PR 2 title message',
|
||||||
htmlURL: '',
|
htmlURL: '',
|
||||||
baseBranch: '',
|
baseBranch: '',
|
||||||
|
createdAt: moment(),
|
||||||
mergedAt: moment(),
|
mergedAt: moment(),
|
||||||
mergeCommitSha: 'sha1-2',
|
mergeCommitSha: 'sha1-2',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
@@ -295,13 +314,15 @@ pullRequestsWithLabels.push(
|
|||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body for this matter',
|
body: 'no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
requestedReviewers: []
|
requestedReviewers: [],
|
||||||
|
status: "merged"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
number: 3,
|
number: 3,
|
||||||
title: '[ABC-1234] - this is a PR 3 title message',
|
title: '[ABC-1234] - this is a PR 3 title message',
|
||||||
htmlURL: '',
|
htmlURL: '',
|
||||||
baseBranch: '',
|
baseBranch: '',
|
||||||
|
createdAt: moment(),
|
||||||
mergedAt: moment().add(1, 'days'),
|
mergedAt: moment().add(1, 'days'),
|
||||||
mergeCommitSha: 'sha1-3',
|
mergeCommitSha: 'sha1-3',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
@@ -310,13 +331,15 @@ pullRequestsWithLabels.push(
|
|||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body for this matter',
|
body: 'no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
requestedReviewers: []
|
requestedReviewers: [],
|
||||||
|
status: "merged"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
number: 4,
|
number: 4,
|
||||||
title: '[AB-404] - not found label',
|
title: '[AB-404] - not found label',
|
||||||
htmlURL: '',
|
htmlURL: '',
|
||||||
baseBranch: '',
|
baseBranch: '',
|
||||||
|
createdAt: moment(),
|
||||||
mergedAt: moment(),
|
mergedAt: moment(),
|
||||||
mergeCommitSha: 'sha1-4',
|
mergeCommitSha: 'sha1-4',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
@@ -325,7 +348,8 @@ pullRequestsWithLabels.push(
|
|||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body for this matter',
|
body: 'no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
requestedReviewers: []
|
requestedReviewers: [],
|
||||||
|
status: "merged"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -354,6 +378,7 @@ it('Match multiple labels exhaustive for category', async () => {
|
|||||||
repo: 'test-repo',
|
repo: 'test-repo',
|
||||||
fromTag: '1.0.0',
|
fromTag: '1.0.0',
|
||||||
toTag: '2.0.0',
|
toTag: '2.0.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration: customConfig
|
configuration: customConfig
|
||||||
@@ -377,6 +402,7 @@ it('Deduplicate duplicated PRs', async () => {
|
|||||||
repo: 'test-repo',
|
repo: 'test-repo',
|
||||||
fromTag: '1.0.0',
|
fromTag: '1.0.0',
|
||||||
toTag: '2.0.0',
|
toTag: '2.0.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration: customConfig
|
configuration: customConfig
|
||||||
@@ -401,6 +427,7 @@ it('Deduplicate duplicated PRs DESC', async () => {
|
|||||||
repo: 'test-repo',
|
repo: 'test-repo',
|
||||||
fromTag: '1.0.0',
|
fromTag: '1.0.0',
|
||||||
toTag: '2.0.0',
|
toTag: '2.0.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration: customConfig
|
configuration: customConfig
|
||||||
@@ -421,6 +448,7 @@ it('Commit SHA-1 in commitMode', async () => {
|
|||||||
repo: 'test-repo',
|
repo: 'test-repo',
|
||||||
fromTag: '1.0.0',
|
fromTag: '1.0.0',
|
||||||
toTag: '2.0.0',
|
toTag: '2.0.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: true,
|
commitMode: true,
|
||||||
configuration: customConfig
|
configuration: customConfig
|
||||||
@@ -440,6 +468,7 @@ it('Release Diff', async () => {
|
|||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: 'v2.8.0',
|
fromTag: 'v2.8.0',
|
||||||
toTag: 'v2.8.1',
|
toTag: 'v2.8.1',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: true,
|
commitMode: true,
|
||||||
configuration: customConfig
|
configuration: customConfig
|
||||||
@@ -477,6 +506,7 @@ it('Use exclude labels to not include a PR within a category.', async () => {
|
|||||||
repo: 'test-repo',
|
repo: 'test-repo',
|
||||||
fromTag: '1.0.0',
|
fromTag: '1.0.0',
|
||||||
toTag: '2.0.0',
|
toTag: '2.0.0',
|
||||||
|
includeOpen: false,
|
||||||
failOnError: false,
|
failOnError: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration: customConfig
|
configuration: customConfig
|
||||||
|
|||||||
+11
@@ -17,6 +17,9 @@ inputs:
|
|||||||
description: 'Defines the previous tag to compare against'
|
description: 'Defines the previous tag to compare against'
|
||||||
toTag:
|
toTag:
|
||||||
description: 'Defines the newly tag created'
|
description: 'Defines the newly tag created'
|
||||||
|
includeOpen:
|
||||||
|
description: 'Defines if the changelog should include open PRs'
|
||||||
|
default: "false"
|
||||||
ignorePreReleases:
|
ignorePreReleases:
|
||||||
description: 'Defines if the action will only use full releases to compare against (Only used if fromTag is not defined). E.g. for 1.0.1... 1.0.0-rc02 <- ignore, 1.0.0 <- pick'
|
description: 'Defines if the action will only use full releases to compare against (Only used if fromTag is not defined). E.g. for 1.0.1... 1.0.0-rc02 <- ignore, 1.0.0 <- pick'
|
||||||
default: "false"
|
default: "false"
|
||||||
@@ -35,6 +38,8 @@ inputs:
|
|||||||
outputs:
|
outputs:
|
||||||
changelog:
|
changelog:
|
||||||
description: The built release changelog built from the merged pull requests
|
description: The built release changelog built from the merged pull requests
|
||||||
|
pull_requests:
|
||||||
|
description: A comma seperated list of PR numbers that were merged
|
||||||
owner:
|
owner:
|
||||||
description: Specifies the owner of the repository processed
|
description: Specifies the owner of the repository processed
|
||||||
repo:
|
repo:
|
||||||
@@ -45,6 +50,12 @@ outputs:
|
|||||||
description: Defines the `toTag` which describes the upper bound to process pull request for
|
description: Defines the `toTag` which describes the upper bound to process pull request for
|
||||||
failed:
|
failed:
|
||||||
description: Defines if there was an issue with the action run, and the changelog may not have been generated correctly. [true, false]
|
description: Defines if there was an issue with the action run, and the changelog may not have been generated correctly. [true, false]
|
||||||
|
categorized_prs:
|
||||||
|
description: Count of categorized pull requests
|
||||||
|
uncategorized_prs:
|
||||||
|
description: Count of uncategorized pull requests
|
||||||
|
open_prs:
|
||||||
|
description: Count of open pull requests. Only fetched if `includeOpen` is enabled.
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node16'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"title": "## 🚀 Features Merged",
|
||||||
|
"labels": ["feature"],
|
||||||
|
"exclude_labels": ["--rcba-open"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## 🚀 Features Open",
|
||||||
|
"labels": ["feature", "--rcba-open"],
|
||||||
|
"exhaustive": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"template": "${{CHANGELOG}}",
|
||||||
|
"pr_template": "- ${{TITLE}} -- (#${{NUMBER}}) [${{STATUS}}] {${{LABELS}}}"
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"title": "## 🚀 Features",
|
||||||
|
"labels": ["feature"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"template": "${{CHANGELOG}}\n\n\nUncategorized\n${{UNCATEGORIZED}}\n\n\nOpen\n${{OPEN}}",
|
||||||
|
"pr_template": "- ${{TITLE}} (#${{NUMBER}}) ${{STATUS}}"
|
||||||
|
}
|
||||||
+113
-25
@@ -377,10 +377,11 @@ function run() {
|
|||||||
const fromTag = core.getInput('fromTag');
|
const fromTag = core.getInput('fromTag');
|
||||||
const toTag = core.getInput('toTag');
|
const toTag = core.getInput('toTag');
|
||||||
// read in flags
|
// read in flags
|
||||||
|
const includeOpen = core.getInput('includeOpen') === 'true';
|
||||||
const ignorePreReleases = core.getInput('ignorePreReleases') === 'true';
|
const ignorePreReleases = core.getInput('ignorePreReleases') === 'true';
|
||||||
const failOnError = core.getInput('failOnError') === 'true';
|
const failOnError = core.getInput('failOnError') === 'true';
|
||||||
const commitMode = core.getInput('commitMode') === 'true';
|
const commitMode = core.getInput('commitMode') === 'true';
|
||||||
const result = yield new releaseNotesBuilder_1.ReleaseNotesBuilder(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, failOnError, ignorePreReleases, commitMode, configuration).build();
|
const result = yield new releaseNotesBuilder_1.ReleaseNotesBuilder(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen, failOnError, ignorePreReleases, commitMode, configuration).build();
|
||||||
core.setOutput('changelog', result);
|
core.setOutput('changelog', result);
|
||||||
// write the result in changelog to file if possible
|
// write the result in changelog to file if possible
|
||||||
const outputFile = core.getInput('outputFile');
|
const outputFile = core.getInput('outputFile');
|
||||||
@@ -487,7 +488,7 @@ class PullRequests {
|
|||||||
const response = _c.value;
|
const response = _c.value;
|
||||||
const prs = response.data;
|
const prs = response.data;
|
||||||
for (const pr of prs.filter(p => !!p.merged_at)) {
|
for (const pr of prs.filter(p => !!p.merged_at)) {
|
||||||
mergedPRs.push(mapPullRequest(pr));
|
mergedPRs.push(mapPullRequest(pr, 'merged'));
|
||||||
}
|
}
|
||||||
const firstPR = prs[0];
|
const firstPR = prs[0];
|
||||||
if (firstPR === undefined ||
|
if (firstPR === undefined ||
|
||||||
@@ -511,15 +512,56 @@ class PullRequests {
|
|||||||
return sortPullRequests(mergedPRs, true);
|
return sortPullRequests(mergedPRs, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
getOpen(owner, repo, maxPullRequests) {
|
||||||
|
var e_2, _a;
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const openPrs = [];
|
||||||
|
const options = this.octokit.pulls.list.endpoint.merge({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
state: 'open',
|
||||||
|
sort: 'created',
|
||||||
|
per_page: '100',
|
||||||
|
direction: 'desc'
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
for (var _b = __asyncValues(this.octokit.paginate.iterator(options)), _c; _c = yield _b.next(), !_c.done;) {
|
||||||
|
const response = _c.value;
|
||||||
|
const prs = response.data;
|
||||||
|
for (const pr of prs) {
|
||||||
|
openPrs.push(mapPullRequest(pr, 'open'));
|
||||||
|
}
|
||||||
|
const firstPR = prs[0];
|
||||||
|
if (firstPR === undefined || openPrs.length >= maxPullRequests) {
|
||||||
|
if (openPrs.length >= maxPullRequests) {
|
||||||
|
core.warning(`⚠️ Reached 'maxPullRequests' count ${maxPullRequests}`);
|
||||||
|
}
|
||||||
|
// bail out early to not keep iterating on PRs super old
|
||||||
|
return sortPullRequests(openPrs, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
if (_c && !_c.done && (_a = _b.return)) yield _a.call(_b);
|
||||||
|
}
|
||||||
|
finally { if (e_2) throw e_2.error; }
|
||||||
|
}
|
||||||
|
return sortPullRequests(openPrs, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.PullRequests = PullRequests;
|
exports.PullRequests = PullRequests;
|
||||||
function sortPullRequests(pullRequests, ascending) {
|
function sortPullRequests(pullRequests, ascending) {
|
||||||
if (ascending) {
|
if (ascending) {
|
||||||
pullRequests.sort((a, b) => {
|
pullRequests.sort((a, b) => {
|
||||||
if (a.mergedAt.isBefore(b.mergedAt)) {
|
const aa = a.mergedAt || a.createdAt;
|
||||||
|
const bb = b.mergedAt || b.createdAt;
|
||||||
|
if (aa.isBefore(bb)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (b.mergedAt.isBefore(a.mergedAt)) {
|
else if (bb.isBefore(aa)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -527,10 +569,12 @@ function sortPullRequests(pullRequests, ascending) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pullRequests.sort((b, a) => {
|
pullRequests.sort((b, a) => {
|
||||||
if (a.mergedAt.isBefore(b.mergedAt)) {
|
const aa = a.mergedAt || a.createdAt;
|
||||||
|
const bb = b.mergedAt || b.createdAt;
|
||||||
|
if (aa.isBefore(bb)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (b.mergedAt.isBefore(a.mergedAt)) {
|
else if (bb.isBefore(aa)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -539,22 +583,29 @@ function sortPullRequests(pullRequests, ascending) {
|
|||||||
return pullRequests;
|
return pullRequests;
|
||||||
}
|
}
|
||||||
exports.sortPullRequests = sortPullRequests;
|
exports.sortPullRequests = sortPullRequests;
|
||||||
const mapPullRequest = (pr) => {
|
// helper function to add a special open label to prs not merged.
|
||||||
|
function attachSpeciaLabels(status, labels) {
|
||||||
|
labels.add(`--rcba-${status}`);
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
const mapPullRequest = (pr, status = 'open') => {
|
||||||
var _a, _b, _c, _d, _e;
|
var _a, _b, _c, _d, _e;
|
||||||
return ({
|
return ({
|
||||||
number: pr.number,
|
number: pr.number,
|
||||||
title: pr.title,
|
title: pr.title,
|
||||||
htmlURL: pr.html_url,
|
htmlURL: pr.html_url,
|
||||||
baseBranch: pr.base.ref,
|
baseBranch: pr.base.ref,
|
||||||
mergedAt: (0, moment_1.default)(pr.merged_at),
|
createdAt: (0, moment_1.default)(pr.created_at),
|
||||||
|
mergedAt: pr.merged_at ? (0, moment_1.default)(pr.merged_at) : null,
|
||||||
mergeCommitSha: pr.merge_commit_sha || '',
|
mergeCommitSha: pr.merge_commit_sha || '',
|
||||||
author: ((_a = pr.user) === null || _a === void 0 ? void 0 : _a.login) || '',
|
author: ((_a = pr.user) === null || _a === void 0 ? void 0 : _a.login) || '',
|
||||||
repoName: pr.base.repo.full_name,
|
repoName: pr.base.repo.full_name,
|
||||||
labels: new Set(((_b = pr.labels) === null || _b === void 0 ? void 0 : _b.map(lbl => { var _a; return ((_a = lbl.name) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase('en')) || ''; })) || []),
|
labels: attachSpeciaLabels(status, new Set(((_b = pr.labels) === null || _b === void 0 ? void 0 : _b.map(lbl => { var _a; return ((_a = lbl.name) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase('en')) || ''; })) || [])),
|
||||||
milestone: ((_c = pr.milestone) === null || _c === void 0 ? void 0 : _c.title) || '',
|
milestone: ((_c = pr.milestone) === null || _c === void 0 ? void 0 : _c.title) || '',
|
||||||
body: pr.body || '',
|
body: pr.body || '',
|
||||||
assignees: ((_d = pr.assignees) === null || _d === void 0 ? void 0 : _d.map(asignee => (asignee === null || asignee === void 0 ? void 0 : asignee.login) || '')) || [],
|
assignees: ((_d = pr.assignees) === null || _d === void 0 ? void 0 : _d.map(asignee => (asignee === null || asignee === void 0 ? void 0 : asignee.login) || '')) || [],
|
||||||
requestedReviewers: ((_e = pr.requested_reviewers) === null || _e === void 0 ? void 0 : _e.map(reviewer => (reviewer === null || reviewer === void 0 ? void 0 : reviewer.login) || '')) || []
|
requestedReviewers: ((_e = pr.requested_reviewers) === null || _e === void 0 ? void 0 : _e.map(reviewer => (reviewer === null || reviewer === void 0 ? void 0 : reviewer.login) || '')) || [],
|
||||||
|
status
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -663,7 +714,7 @@ class ReleaseNotes {
|
|||||||
}
|
}
|
||||||
getMergedPullRequests(octokit) {
|
getMergedPullRequests(octokit) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const { owner, repo, configuration } = this.options;
|
const { owner, repo, includeOpen, configuration } = this.options;
|
||||||
const commits = yield this.getCommitHistory(octokit);
|
const commits = yield this.getCommitHistory(octokit);
|
||||||
if (commits.length === 0) {
|
if (commits.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
@@ -690,21 +741,33 @@ class ReleaseNotes {
|
|||||||
const releaseCommitHashes = prCommits.map(commmit => {
|
const releaseCommitHashes = prCommits.map(commmit => {
|
||||||
return commmit.sha;
|
return commmit.sha;
|
||||||
});
|
});
|
||||||
|
// filter out pull requests not associated with this release
|
||||||
|
const mergedPullRequests = pullRequests.filter(pr => {
|
||||||
|
return releaseCommitHashes.includes(pr.mergeCommitSha);
|
||||||
|
});
|
||||||
|
let allPullRequests = mergedPullRequests;
|
||||||
|
if (includeOpen) {
|
||||||
|
// retrieve all open pull requests
|
||||||
|
const openPullRequests = yield pullRequestsApi.getOpen(owner, repo, configuration.max_pull_requests ||
|
||||||
|
configuration_1.DefaultConfiguration.max_pull_requests);
|
||||||
|
core.info(`ℹ️ Retrieved ${openPullRequests.length} open PRs for ${owner}/${repo}`);
|
||||||
|
// all pull requests
|
||||||
|
allPullRequests = allPullRequests.concat(openPullRequests);
|
||||||
|
core.info(`ℹ️ Retrieved ${allPullRequests.length} total PRs for ${owner}/${repo}`);
|
||||||
|
}
|
||||||
// retrieve base branches we allow
|
// retrieve base branches we allow
|
||||||
const baseBranches = configuration.base_branches || configuration_1.DefaultConfiguration.base_branches;
|
const baseBranches = configuration.base_branches || configuration_1.DefaultConfiguration.base_branches;
|
||||||
const baseBranchPatterns = baseBranches.map(baseBranch => {
|
const baseBranchPatterns = baseBranches.map(baseBranch => {
|
||||||
return new RegExp(baseBranch.replace('\\\\', '\\'), 'gu');
|
return new RegExp(baseBranch.replace('\\\\', '\\'), 'gu');
|
||||||
});
|
});
|
||||||
// return only the pull requests associated with this release
|
// return only prs if the baseBranch is matching the configuration
|
||||||
// and if the baseBranch is matching the configuration
|
return allPullRequests.filter(pr => {
|
||||||
return pullRequests.filter(pr => {
|
if (baseBranches.length !== 0) {
|
||||||
let keep = releaseCommitHashes.includes(pr.mergeCommitSha);
|
return baseBranchPatterns.some(pattern => {
|
||||||
if (keep && baseBranches.length !== 0) {
|
|
||||||
keep = baseBranchPatterns.some(pattern => {
|
|
||||||
return pr.baseBranch.match(pattern) !== null;
|
return pr.baseBranch.match(pattern) !== null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return keep;
|
return true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -724,6 +787,7 @@ class ReleaseNotes {
|
|||||||
title: commit.summary,
|
title: commit.summary,
|
||||||
htmlURL: '',
|
htmlURL: '',
|
||||||
baseBranch: '',
|
baseBranch: '',
|
||||||
|
createdAt: commit.date,
|
||||||
mergedAt: commit.date,
|
mergedAt: commit.date,
|
||||||
mergeCommitSha: commit.sha,
|
mergeCommitSha: commit.sha,
|
||||||
author: commit.author || '',
|
author: commit.author || '',
|
||||||
@@ -732,7 +796,8 @@ class ReleaseNotes {
|
|||||||
milestone: '',
|
milestone: '',
|
||||||
body: commit.message || '',
|
body: commit.message || '',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
requestedReviewers: []
|
requestedReviewers: [],
|
||||||
|
status: 'merged'
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -790,7 +855,7 @@ const tags_1 = __nccwpck_require__(7532);
|
|||||||
const utils_1 = __nccwpck_require__(918);
|
const utils_1 = __nccwpck_require__(918);
|
||||||
const transform_1 = __nccwpck_require__(1644);
|
const transform_1 = __nccwpck_require__(1644);
|
||||||
class ReleaseNotesBuilder {
|
class ReleaseNotesBuilder {
|
||||||
constructor(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, failOnError, ignorePreReleases, commitMode, configuration) {
|
constructor(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen, failOnError, ignorePreReleases, commitMode, configuration) {
|
||||||
this.baseUrl = baseUrl;
|
this.baseUrl = baseUrl;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.repositoryPath = repositoryPath;
|
this.repositoryPath = repositoryPath;
|
||||||
@@ -798,6 +863,7 @@ class ReleaseNotesBuilder {
|
|||||||
this.repo = repo;
|
this.repo = repo;
|
||||||
this.fromTag = fromTag;
|
this.fromTag = fromTag;
|
||||||
this.toTag = toTag;
|
this.toTag = toTag;
|
||||||
|
this.includeOpen = includeOpen;
|
||||||
this.failOnError = failOnError;
|
this.failOnError = failOnError;
|
||||||
this.ignorePreReleases = ignorePreReleases;
|
this.ignorePreReleases = ignorePreReleases;
|
||||||
this.commitMode = commitMode;
|
this.commitMode = commitMode;
|
||||||
@@ -857,6 +923,7 @@ class ReleaseNotesBuilder {
|
|||||||
repo: this.repo,
|
repo: this.repo,
|
||||||
fromTag: this.fromTag,
|
fromTag: this.fromTag,
|
||||||
toTag: this.toTag,
|
toTag: this.toTag,
|
||||||
|
includeOpen: this.includeOpen,
|
||||||
failOnError: this.failOnError,
|
failOnError: this.failOnError,
|
||||||
commitMode: this.commitMode,
|
commitMode: this.commitMode,
|
||||||
configuration: this.configuration
|
configuration: this.configuration
|
||||||
@@ -1293,6 +1360,7 @@ function buildChangelog(prs, options) {
|
|||||||
}
|
}
|
||||||
const categorizedPrs = [];
|
const categorizedPrs = [];
|
||||||
const ignoredPrs = [];
|
const ignoredPrs = [];
|
||||||
|
const openPrs = [];
|
||||||
const uncategorizedPrs = [];
|
const uncategorizedPrs = [];
|
||||||
// bring elements in order
|
// bring elements in order
|
||||||
for (const [pr, body] of transformedMap) {
|
for (const [pr, body] of transformedMap) {
|
||||||
@@ -1300,6 +1368,9 @@ function buildChangelog(prs, options) {
|
|||||||
ignoredPrs.push(body);
|
ignoredPrs.push(body);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (pr.status === 'open') {
|
||||||
|
openPrs.push(body);
|
||||||
|
}
|
||||||
let matched = false;
|
let matched = false;
|
||||||
for (const [category, pullRequests] of categorized) {
|
for (const [category, pullRequests] of categorized) {
|
||||||
// check if any exclude label matches
|
// check if any exclude label matches
|
||||||
@@ -1372,6 +1443,19 @@ function buildChangelog(prs, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
core.setOutput('uncategorized_prs', uncategorizedPrs.length);
|
core.setOutput('uncategorized_prs', uncategorizedPrs.length);
|
||||||
|
let changelogOpen = '';
|
||||||
|
if (openPrs.length > 0) {
|
||||||
|
for (const pr of openPrs) {
|
||||||
|
changelogOpen = `${changelogOpen + pr}\n`;
|
||||||
|
}
|
||||||
|
core.info(`✒️ Wrote ${openPrs.length} open pull requests down`);
|
||||||
|
if (core.isDebug()) {
|
||||||
|
for (const pr of openPrs) {
|
||||||
|
core.debug(` ${pr}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core.setOutput('open_prs', openPrs.length);
|
||||||
|
}
|
||||||
let changelogIgnored = '';
|
let changelogIgnored = '';
|
||||||
for (const pr of ignoredPrs) {
|
for (const pr of ignoredPrs) {
|
||||||
changelogIgnored = `${changelogIgnored + pr}\n`;
|
changelogIgnored = `${changelogIgnored + pr}\n`;
|
||||||
@@ -1386,10 +1470,12 @@ function buildChangelog(prs, options) {
|
|||||||
let transformedChangelog = config.template || configuration_1.DefaultConfiguration.template;
|
let transformedChangelog = config.template || configuration_1.DefaultConfiguration.template;
|
||||||
transformedChangelog = transformedChangelog.replace(/\${{CHANGELOG}}/g, changelog);
|
transformedChangelog = transformedChangelog.replace(/\${{CHANGELOG}}/g, changelog);
|
||||||
transformedChangelog = transformedChangelog.replace(/\${{UNCATEGORIZED}}/g, changelogUncategorized);
|
transformedChangelog = transformedChangelog.replace(/\${{UNCATEGORIZED}}/g, changelogUncategorized);
|
||||||
|
transformedChangelog = transformedChangelog.replace(/\${{OPEN}}/g, changelogOpen);
|
||||||
transformedChangelog = transformedChangelog.replace(/\${{IGNORED}}/g, changelogIgnored);
|
transformedChangelog = transformedChangelog.replace(/\${{IGNORED}}/g, changelogIgnored);
|
||||||
// fill other placeholders
|
// fill other placeholders
|
||||||
transformedChangelog = transformedChangelog.replace(/\${{CATEGORIZED_COUNT}}/g, categorizedPrs.length.toString());
|
transformedChangelog = transformedChangelog.replace(/\${{CATEGORIZED_COUNT}}/g, categorizedPrs.length.toString());
|
||||||
transformedChangelog = transformedChangelog.replace(/\${{UNCATEGORIZED_COUNT}}/g, uncategorizedPrs.length.toString());
|
transformedChangelog = transformedChangelog.replace(/\${{UNCATEGORIZED_COUNT}}/g, uncategorizedPrs.length.toString());
|
||||||
|
transformedChangelog = transformedChangelog.replace(/\${{OPEN_COUNT}}/g, openPrs.length.toString());
|
||||||
transformedChangelog = transformedChangelog.replace(/\${{IGNORED_COUNT}}/g, ignoredPrs.length.toString());
|
transformedChangelog = transformedChangelog.replace(/\${{IGNORED_COUNT}}/g, ignoredPrs.length.toString());
|
||||||
transformedChangelog = fillAdditionalPlaceholders(transformedChangelog, options);
|
transformedChangelog = fillAdditionalPlaceholders(transformedChangelog, options);
|
||||||
core.info(`ℹ️ Filled template`);
|
core.info(`ℹ️ Filled template`);
|
||||||
@@ -1413,19 +1499,21 @@ function haveEveryElements(arr1, arr2) {
|
|||||||
return arr1.every(item => arr2.has(item));
|
return arr1.every(item => arr2.has(item));
|
||||||
}
|
}
|
||||||
function fillTemplate(pr, template) {
|
function fillTemplate(pr, template) {
|
||||||
var _a, _b, _c;
|
var _a, _b, _c, _d, _e;
|
||||||
let transformed = template;
|
let transformed = template;
|
||||||
transformed = transformed.replace(/\${{NUMBER}}/g, pr.number.toString());
|
transformed = transformed.replace(/\${{NUMBER}}/g, pr.number.toString());
|
||||||
transformed = transformed.replace(/\${{TITLE}}/g, pr.title);
|
transformed = transformed.replace(/\${{TITLE}}/g, pr.title);
|
||||||
transformed = transformed.replace(/\${{URL}}/g, pr.htmlURL);
|
transformed = transformed.replace(/\${{URL}}/g, pr.htmlURL);
|
||||||
transformed = transformed.replace(/\${{MERGED_AT}}/g, pr.mergedAt.toISOString());
|
transformed = transformed.replace(/\${{STATUS}}/g, pr.status);
|
||||||
|
transformed = transformed.replace(/\${{CREATED_AT}}/g, pr.createdAt.toISOString());
|
||||||
|
transformed = transformed.replace(/\${{MERGED_AT}}/g, ((_a = pr.mergedAt) === null || _a === void 0 ? void 0 : _a.toISOString()) || '');
|
||||||
transformed = transformed.replace(/\${{MERGE_SHA}}/g, pr.mergeCommitSha);
|
transformed = transformed.replace(/\${{MERGE_SHA}}/g, pr.mergeCommitSha);
|
||||||
transformed = transformed.replace(/\${{AUTHOR}}/g, pr.author);
|
transformed = transformed.replace(/\${{AUTHOR}}/g, pr.author);
|
||||||
transformed = transformed.replace(/\${{LABELS}}/g, ((_a = [...pr.labels]) === null || _a === void 0 ? void 0 : _a.join(', ')) || '');
|
transformed = transformed.replace(/\${{LABELS}}/g, ((_c = (_b = [...pr.labels]) === null || _b === void 0 ? void 0 : _b.filter(l => !l.startsWith('--rcba-'))) === null || _c === void 0 ? void 0 : _c.join(', ')) || '');
|
||||||
transformed = transformed.replace(/\${{MILESTONE}}/g, pr.milestone || '');
|
transformed = transformed.replace(/\${{MILESTONE}}/g, pr.milestone || '');
|
||||||
transformed = transformed.replace(/\${{BODY}}/g, pr.body);
|
transformed = transformed.replace(/\${{BODY}}/g, pr.body);
|
||||||
transformed = transformed.replace(/\${{ASSIGNEES}}/g, ((_b = pr.assignees) === null || _b === void 0 ? void 0 : _b.join(', ')) || '');
|
transformed = transformed.replace(/\${{ASSIGNEES}}/g, ((_d = pr.assignees) === null || _d === void 0 ? void 0 : _d.join(', ')) || '');
|
||||||
transformed = transformed.replace(/\${{REVIEWERS}}/g, ((_c = pr.requestedReviewers) === null || _c === void 0 ? void 0 : _c.join(', ')) || '');
|
transformed = transformed.replace(/\${{REVIEWERS}}/g, ((_e = pr.requestedReviewers) === null || _e === void 0 ? void 0 : _e.join(', ')) || '');
|
||||||
return transformed;
|
return transformed;
|
||||||
}
|
}
|
||||||
function transform(filled, transformers) {
|
function transform(filled, transformers) {
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -32,6 +32,7 @@ async function run(): Promise<void> {
|
|||||||
const fromTag = core.getInput('fromTag')
|
const fromTag = core.getInput('fromTag')
|
||||||
const toTag = core.getInput('toTag')
|
const toTag = core.getInput('toTag')
|
||||||
// read in flags
|
// read in flags
|
||||||
|
const includeOpen = core.getInput('includeOpen') === 'true'
|
||||||
const ignorePreReleases = core.getInput('ignorePreReleases') === 'true'
|
const ignorePreReleases = core.getInput('ignorePreReleases') === 'true'
|
||||||
const failOnError = core.getInput('failOnError') === 'true'
|
const failOnError = core.getInput('failOnError') === 'true'
|
||||||
const commitMode = core.getInput('commitMode') === 'true'
|
const commitMode = core.getInput('commitMode') === 'true'
|
||||||
@@ -44,6 +45,7 @@ async function run(): Promise<void> {
|
|||||||
repo,
|
repo,
|
||||||
fromTag,
|
fromTag,
|
||||||
toTag,
|
toTag,
|
||||||
|
includeOpen,
|
||||||
failOnError,
|
failOnError,
|
||||||
ignorePreReleases,
|
ignorePreReleases,
|
||||||
commitMode,
|
commitMode,
|
||||||
|
|||||||
+68
-11
@@ -8,7 +8,8 @@ export interface PullRequestInfo {
|
|||||||
title: string
|
title: string
|
||||||
htmlURL: string
|
htmlURL: string
|
||||||
baseBranch: string
|
baseBranch: string
|
||||||
mergedAt: moment.Moment
|
createdAt: moment.Moment
|
||||||
|
mergedAt: moment.Moment | null
|
||||||
mergeCommitSha: string
|
mergeCommitSha: string
|
||||||
author: string
|
author: string
|
||||||
repoName: string
|
repoName: string
|
||||||
@@ -17,6 +18,7 @@ export interface PullRequestInfo {
|
|||||||
body: string
|
body: string
|
||||||
assignees: string[]
|
assignees: string[]
|
||||||
requestedReviewers: string[]
|
requestedReviewers: string[]
|
||||||
|
status: 'open' | 'merged'
|
||||||
}
|
}
|
||||||
|
|
||||||
type PullData = RestEndpointMethodTypes['pulls']['get']['response']['data']
|
type PullData = RestEndpointMethodTypes['pulls']['get']['response']['data']
|
||||||
@@ -69,7 +71,7 @@ export class PullRequests {
|
|||||||
const prs: PullsListData = response.data as PullsListData
|
const prs: PullsListData = response.data as PullsListData
|
||||||
|
|
||||||
for (const pr of prs.filter(p => !!p.merged_at)) {
|
for (const pr of prs.filter(p => !!p.merged_at)) {
|
||||||
mergedPRs.push(mapPullRequest(pr))
|
mergedPRs.push(mapPullRequest(pr, 'merged'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstPR = prs[0]
|
const firstPR = prs[0]
|
||||||
@@ -89,6 +91,42 @@ export class PullRequests {
|
|||||||
|
|
||||||
return sortPullRequests(mergedPRs, true)
|
return sortPullRequests(mergedPRs, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getOpen(
|
||||||
|
owner: string,
|
||||||
|
repo: string,
|
||||||
|
maxPullRequests: number
|
||||||
|
): Promise<PullRequestInfo[]> {
|
||||||
|
const openPrs: PullRequestInfo[] = []
|
||||||
|
const options = this.octokit.pulls.list.endpoint.merge({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
state: 'open',
|
||||||
|
sort: 'created',
|
||||||
|
per_page: '100',
|
||||||
|
direction: 'desc'
|
||||||
|
})
|
||||||
|
|
||||||
|
for await (const response of this.octokit.paginate.iterator(options)) {
|
||||||
|
const prs: PullsListData = response.data as PullsListData
|
||||||
|
|
||||||
|
for (const pr of prs) {
|
||||||
|
openPrs.push(mapPullRequest(pr, 'open'))
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstPR = prs[0]
|
||||||
|
if (firstPR === undefined || openPrs.length >= maxPullRequests) {
|
||||||
|
if (openPrs.length >= maxPullRequests) {
|
||||||
|
core.warning(`⚠️ Reached 'maxPullRequests' count ${maxPullRequests}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bail out early to not keep iterating on PRs super old
|
||||||
|
return sortPullRequests(openPrs, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortPullRequests(openPrs, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sortPullRequests(
|
export function sortPullRequests(
|
||||||
@@ -97,18 +135,22 @@ export function sortPullRequests(
|
|||||||
): PullRequestInfo[] {
|
): PullRequestInfo[] {
|
||||||
if (ascending) {
|
if (ascending) {
|
||||||
pullRequests.sort((a, b) => {
|
pullRequests.sort((a, b) => {
|
||||||
if (a.mergedAt.isBefore(b.mergedAt)) {
|
const aa = a.mergedAt || a.createdAt
|
||||||
|
const bb = b.mergedAt || b.createdAt
|
||||||
|
if (aa.isBefore(bb)) {
|
||||||
return -1
|
return -1
|
||||||
} else if (b.mergedAt.isBefore(a.mergedAt)) {
|
} else if (bb.isBefore(aa)) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
pullRequests.sort((b, a) => {
|
pullRequests.sort((b, a) => {
|
||||||
if (a.mergedAt.isBefore(b.mergedAt)) {
|
const aa = a.mergedAt || a.createdAt
|
||||||
|
const bb = b.mergedAt || b.createdAt
|
||||||
|
if (aa.isBefore(bb)) {
|
||||||
return -1
|
return -1
|
||||||
} else if (b.mergedAt.isBefore(a.mergedAt)) {
|
} else if (bb.isBefore(aa)) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
@@ -117,23 +159,38 @@ export function sortPullRequests(
|
|||||||
return pullRequests
|
return pullRequests
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helper function to add a special open label to prs not merged.
|
||||||
|
function attachSpeciaLabels(
|
||||||
|
status: 'open' | 'merged',
|
||||||
|
labels: Set<string>
|
||||||
|
): Set<string> {
|
||||||
|
labels.add(`--rcba-${status}`)
|
||||||
|
return labels
|
||||||
|
}
|
||||||
|
|
||||||
const mapPullRequest = (
|
const mapPullRequest = (
|
||||||
pr: PullData | Unpacked<PullsListData>
|
pr: PullData | Unpacked<PullsListData>,
|
||||||
|
status: 'open' | 'merged' = 'open'
|
||||||
): PullRequestInfo => ({
|
): PullRequestInfo => ({
|
||||||
number: pr.number,
|
number: pr.number,
|
||||||
title: pr.title,
|
title: pr.title,
|
||||||
htmlURL: pr.html_url,
|
htmlURL: pr.html_url,
|
||||||
baseBranch: pr.base.ref,
|
baseBranch: pr.base.ref,
|
||||||
mergedAt: moment(pr.merged_at),
|
createdAt: moment(pr.created_at),
|
||||||
|
mergedAt: pr.merged_at ? moment(pr.merged_at) : null,
|
||||||
mergeCommitSha: pr.merge_commit_sha || '',
|
mergeCommitSha: pr.merge_commit_sha || '',
|
||||||
author: pr.user?.login || '',
|
author: pr.user?.login || '',
|
||||||
repoName: pr.base.repo.full_name,
|
repoName: pr.base.repo.full_name,
|
||||||
labels: new Set(
|
labels: attachSpeciaLabels(
|
||||||
pr.labels?.map(lbl => lbl.name?.toLocaleLowerCase('en') || '') || []
|
status,
|
||||||
|
new Set(
|
||||||
|
pr.labels?.map(lbl => lbl.name?.toLocaleLowerCase('en') || '') || []
|
||||||
|
)
|
||||||
),
|
),
|
||||||
milestone: pr.milestone?.title || '',
|
milestone: pr.milestone?.title || '',
|
||||||
body: pr.body || '',
|
body: pr.body || '',
|
||||||
assignees: pr.assignees?.map(asignee => asignee?.login || '') || [],
|
assignees: pr.assignees?.map(asignee => asignee?.login || '') || [],
|
||||||
requestedReviewers:
|
requestedReviewers:
|
||||||
pr.requested_reviewers?.map(reviewer => reviewer?.login || '') || []
|
pr.requested_reviewers?.map(reviewer => reviewer?.login || '') || [],
|
||||||
|
status
|
||||||
})
|
})
|
||||||
|
|||||||
+37
-9
@@ -11,6 +11,7 @@ export interface ReleaseNotesOptions {
|
|||||||
repo: string // the repository
|
repo: string // the repository
|
||||||
fromTag: string // the tag/ref to start from
|
fromTag: string // the tag/ref to start from
|
||||||
toTag: string // the tag/ref up to
|
toTag: string // the tag/ref up to
|
||||||
|
includeOpen: boolean // defines if we should also fetch open pull requests
|
||||||
failOnError: boolean // defines if we should fail the action in case of an error
|
failOnError: boolean // defines if we should fail the action in case of an error
|
||||||
commitMode: boolean // defines if we use the alternative commit based mode. note: this is only partially supported
|
commitMode: boolean // defines if we use the alternative commit based mode. note: this is only partially supported
|
||||||
configuration: Configuration // the configuration as defined in `configuration.ts`
|
configuration: Configuration // the configuration as defined in `configuration.ts`
|
||||||
@@ -80,7 +81,7 @@ export class ReleaseNotes {
|
|||||||
private async getMergedPullRequests(
|
private async getMergedPullRequests(
|
||||||
octokit: Octokit
|
octokit: Octokit
|
||||||
): Promise<PullRequestInfo[]> {
|
): Promise<PullRequestInfo[]> {
|
||||||
const {owner, repo, configuration} = this.options
|
const {owner, repo, includeOpen, configuration} = this.options
|
||||||
|
|
||||||
const commits = await this.getCommitHistory(octokit)
|
const commits = await this.getCommitHistory(octokit)
|
||||||
if (commits.length === 0) {
|
if (commits.length === 0) {
|
||||||
@@ -133,6 +134,33 @@ export class ReleaseNotes {
|
|||||||
return commmit.sha
|
return commmit.sha
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// filter out pull requests not associated with this release
|
||||||
|
const mergedPullRequests = pullRequests.filter(pr => {
|
||||||
|
return releaseCommitHashes.includes(pr.mergeCommitSha)
|
||||||
|
})
|
||||||
|
|
||||||
|
let allPullRequests = mergedPullRequests
|
||||||
|
if (includeOpen) {
|
||||||
|
// retrieve all open pull requests
|
||||||
|
const openPullRequests = await pullRequestsApi.getOpen(
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
configuration.max_pull_requests ||
|
||||||
|
DefaultConfiguration.max_pull_requests
|
||||||
|
)
|
||||||
|
|
||||||
|
core.info(
|
||||||
|
`ℹ️ Retrieved ${openPullRequests.length} open PRs for ${owner}/${repo}`
|
||||||
|
)
|
||||||
|
|
||||||
|
// all pull requests
|
||||||
|
allPullRequests = allPullRequests.concat(openPullRequests)
|
||||||
|
|
||||||
|
core.info(
|
||||||
|
`ℹ️ Retrieved ${allPullRequests.length} total PRs for ${owner}/${repo}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// retrieve base branches we allow
|
// retrieve base branches we allow
|
||||||
const baseBranches =
|
const baseBranches =
|
||||||
configuration.base_branches || DefaultConfiguration.base_branches
|
configuration.base_branches || DefaultConfiguration.base_branches
|
||||||
@@ -140,16 +168,14 @@ export class ReleaseNotes {
|
|||||||
return new RegExp(baseBranch.replace('\\\\', '\\'), 'gu')
|
return new RegExp(baseBranch.replace('\\\\', '\\'), 'gu')
|
||||||
})
|
})
|
||||||
|
|
||||||
// return only the pull requests associated with this release
|
// return only prs if the baseBranch is matching the configuration
|
||||||
// and if the baseBranch is matching the configuration
|
return allPullRequests.filter(pr => {
|
||||||
return pullRequests.filter(pr => {
|
if (baseBranches.length !== 0) {
|
||||||
let keep = releaseCommitHashes.includes(pr.mergeCommitSha)
|
return baseBranchPatterns.some(pattern => {
|
||||||
if (keep && baseBranches.length !== 0) {
|
|
||||||
keep = baseBranchPatterns.some(pattern => {
|
|
||||||
return pr.baseBranch.match(pattern) !== null
|
return pr.baseBranch.match(pattern) !== null
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return keep
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,6 +203,7 @@ export class ReleaseNotes {
|
|||||||
title: commit.summary,
|
title: commit.summary,
|
||||||
htmlURL: '',
|
htmlURL: '',
|
||||||
baseBranch: '',
|
baseBranch: '',
|
||||||
|
createdAt: commit.date,
|
||||||
mergedAt: commit.date,
|
mergedAt: commit.date,
|
||||||
mergeCommitSha: commit.sha,
|
mergeCommitSha: commit.sha,
|
||||||
author: commit.author || '',
|
author: commit.author || '',
|
||||||
@@ -185,7 +212,8 @@ export class ReleaseNotes {
|
|||||||
milestone: '',
|
milestone: '',
|
||||||
body: commit.message || '',
|
body: commit.message || '',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
requestedReviewers: []
|
requestedReviewers: [],
|
||||||
|
status: 'merged'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export class ReleaseNotesBuilder {
|
|||||||
private repo: string | null,
|
private repo: string | null,
|
||||||
private fromTag: string | null,
|
private fromTag: string | null,
|
||||||
private toTag: string | null,
|
private toTag: string | null,
|
||||||
|
private includeOpen: boolean,
|
||||||
private failOnError: boolean,
|
private failOnError: boolean,
|
||||||
private ignorePreReleases: boolean,
|
private ignorePreReleases: boolean,
|
||||||
private commitMode: boolean,
|
private commitMode: boolean,
|
||||||
@@ -88,6 +89,7 @@ export class ReleaseNotesBuilder {
|
|||||||
repo: this.repo,
|
repo: this.repo,
|
||||||
fromTag: this.fromTag,
|
fromTag: this.fromTag,
|
||||||
toTag: this.toTag,
|
toTag: this.toTag,
|
||||||
|
includeOpen: this.includeOpen,
|
||||||
failOnError: this.failOnError,
|
failOnError: this.failOnError,
|
||||||
commitMode: this.commitMode,
|
commitMode: this.commitMode,
|
||||||
configuration: this.configuration
|
configuration: this.configuration
|
||||||
|
|||||||
+35
-3
@@ -95,6 +95,7 @@ export function buildChangelog(
|
|||||||
|
|
||||||
const categorizedPrs: string[] = []
|
const categorizedPrs: string[] = []
|
||||||
const ignoredPrs: string[] = []
|
const ignoredPrs: string[] = []
|
||||||
|
const openPrs: string[] = []
|
||||||
const uncategorizedPrs: string[] = []
|
const uncategorizedPrs: string[] = []
|
||||||
|
|
||||||
// bring elements in order
|
// bring elements in order
|
||||||
@@ -109,6 +110,10 @@ export function buildChangelog(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pr.status === 'open') {
|
||||||
|
openPrs.push(body)
|
||||||
|
}
|
||||||
|
|
||||||
let matched = false
|
let matched = false
|
||||||
for (const [category, pullRequests] of categorized) {
|
for (const [category, pullRequests] of categorized) {
|
||||||
// check if any exclude label matches
|
// check if any exclude label matches
|
||||||
@@ -206,6 +211,20 @@ export function buildChangelog(
|
|||||||
}
|
}
|
||||||
core.setOutput('uncategorized_prs', uncategorizedPrs.length)
|
core.setOutput('uncategorized_prs', uncategorizedPrs.length)
|
||||||
|
|
||||||
|
let changelogOpen = ''
|
||||||
|
if (openPrs.length > 0) {
|
||||||
|
for (const pr of openPrs) {
|
||||||
|
changelogOpen = `${changelogOpen + pr}\n`
|
||||||
|
}
|
||||||
|
core.info(`✒️ Wrote ${openPrs.length} open pull requests down`)
|
||||||
|
if (core.isDebug()) {
|
||||||
|
for (const pr of openPrs) {
|
||||||
|
core.debug(` ${pr}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core.setOutput('open_prs', openPrs.length)
|
||||||
|
}
|
||||||
|
|
||||||
let changelogIgnored = ''
|
let changelogIgnored = ''
|
||||||
for (const pr of ignoredPrs) {
|
for (const pr of ignoredPrs) {
|
||||||
changelogIgnored = `${changelogIgnored + pr}\n`
|
changelogIgnored = `${changelogIgnored + pr}\n`
|
||||||
@@ -227,6 +246,10 @@ export function buildChangelog(
|
|||||||
/\${{UNCATEGORIZED}}/g,
|
/\${{UNCATEGORIZED}}/g,
|
||||||
changelogUncategorized
|
changelogUncategorized
|
||||||
)
|
)
|
||||||
|
transformedChangelog = transformedChangelog.replace(
|
||||||
|
/\${{OPEN}}/g,
|
||||||
|
changelogOpen
|
||||||
|
)
|
||||||
transformedChangelog = transformedChangelog.replace(
|
transformedChangelog = transformedChangelog.replace(
|
||||||
/\${{IGNORED}}/g,
|
/\${{IGNORED}}/g,
|
||||||
changelogIgnored
|
changelogIgnored
|
||||||
@@ -241,6 +264,10 @@ export function buildChangelog(
|
|||||||
/\${{UNCATEGORIZED_COUNT}}/g,
|
/\${{UNCATEGORIZED_COUNT}}/g,
|
||||||
uncategorizedPrs.length.toString()
|
uncategorizedPrs.length.toString()
|
||||||
)
|
)
|
||||||
|
transformedChangelog = transformedChangelog.replace(
|
||||||
|
/\${{OPEN_COUNT}}/g,
|
||||||
|
openPrs.length.toString()
|
||||||
|
)
|
||||||
transformedChangelog = transformedChangelog.replace(
|
transformedChangelog = transformedChangelog.replace(
|
||||||
/\${{IGNORED_COUNT}}/g,
|
/\${{IGNORED_COUNT}}/g,
|
||||||
ignoredPrs.length.toString()
|
ignoredPrs.length.toString()
|
||||||
@@ -283,15 +310,20 @@ function fillTemplate(pr: PullRequestInfo, template: string): string {
|
|||||||
transformed = transformed.replace(/\${{NUMBER}}/g, pr.number.toString())
|
transformed = transformed.replace(/\${{NUMBER}}/g, pr.number.toString())
|
||||||
transformed = transformed.replace(/\${{TITLE}}/g, pr.title)
|
transformed = transformed.replace(/\${{TITLE}}/g, pr.title)
|
||||||
transformed = transformed.replace(/\${{URL}}/g, pr.htmlURL)
|
transformed = transformed.replace(/\${{URL}}/g, pr.htmlURL)
|
||||||
|
transformed = transformed.replace(/\${{STATUS}}/g, pr.status)
|
||||||
|
transformed = transformed.replace(
|
||||||
|
/\${{CREATED_AT}}/g,
|
||||||
|
pr.createdAt.toISOString()
|
||||||
|
)
|
||||||
transformed = transformed.replace(
|
transformed = transformed.replace(
|
||||||
/\${{MERGED_AT}}/g,
|
/\${{MERGED_AT}}/g,
|
||||||
pr.mergedAt.toISOString()
|
pr.mergedAt?.toISOString() || ''
|
||||||
)
|
)
|
||||||
transformed = transformed.replace(/\${{MERGE_SHA}}/g, pr.mergeCommitSha)
|
transformed = transformed.replace(/\${{MERGE_SHA}}/g, pr.mergeCommitSha)
|
||||||
transformed = transformed.replace(/\${{AUTHOR}}/g, pr.author)
|
transformed = transformed.replace(/\${{AUTHOR}}/g, pr.author)
|
||||||
transformed = transformed.replace(
|
transformed = transformed.replace(
|
||||||
/\${{LABELS}}/g,
|
/\${{LABELS}}/g,
|
||||||
[...pr.labels]?.join(', ') || ''
|
[...pr.labels]?.filter(l => !l.startsWith('--rcba-'))?.join(', ') || ''
|
||||||
)
|
)
|
||||||
transformed = transformed.replace(/\${{MILESTONE}}/g, pr.milestone || '')
|
transformed = transformed.replace(/\${{MILESTONE}}/g, pr.milestone || '')
|
||||||
transformed = transformed.replace(/\${{BODY}}/g, pr.body)
|
transformed = transformed.replace(/\${{BODY}}/g, pr.body)
|
||||||
@@ -384,7 +416,7 @@ function extractValues(
|
|||||||
|
|
||||||
if (extractor.onProperty !== undefined) {
|
if (extractor.onProperty !== undefined) {
|
||||||
let results: string[] = []
|
let results: string[] = []
|
||||||
const list: ('title' | 'author' | 'milestone' | 'body')[] =
|
const list: ('title' | 'author' | 'milestone' | 'body' | 'status')[] =
|
||||||
extractor.onProperty
|
extractor.onProperty
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user