Merge pull request #827 from mikepenz/feature/fetch_release_information

Fetch GitHub release information
This commit is contained in:
Mike Penz
2022-07-26 17:01:01 +02:00
committed by GitHub
14 changed files with 360 additions and 91 deletions
+4 -1
View File
@@ -297,8 +297,9 @@ Table of supported placeholders allowed to be used in the `pr_template` configur
| `${{MILESTONE}}` | Milestone this PR was part of, as assigned on GitHub | | `${{MILESTONE}}` | Milestone this PR was part of, as assigned on GitHub |
| `${{BODY}}` | Description/Body of the pull request as specified on GitHub | | `${{BODY}}` | Description/Body of the pull request as specified on GitHub |
| `${{ASSIGNEES}}` | Login names of assigned GitHub users, joined by `,` | | `${{ASSIGNEES}}` | Login names of assigned GitHub users, joined by `,` |
| `${{REVIEWERS}}` | GitHub Login names of specified reviewers, joined by `,` | | `${{REVIEWERS}}` | GitHub Login names of specified reviewers, joined by `,`. Requires `fetchReviewers` to be enabled. |
| `${{APPROVERS}}` | GitHub Login names of users who approved the PR, joined by `,` | | `${{APPROVERS}}` | GitHub Login names of users who approved the PR, joined by `,` |
| `${{DAYS_SINCE}}` | Days between the 2 releases. Requires `fetchReleaseInformation` to be enabled. |
### Template placeholders ### Template placeholders
@@ -313,7 +314,9 @@ Table of supported placeholders allowed to be used in the `template` and `empty_
| `${{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 |
| `${{FROM_TAG}}` | Defines the 'start' from where the changelog did consider merged pull requests | x | | `${{FROM_TAG}}` | Defines the 'start' from where the changelog did consider merged pull requests | x |
| `${{FROM_TAG_DATE}}` | Defines the date at which the 'start' tag was created | x |
| `${{TO_TAG}}` | Defines until which tag the changelog did consider merged pull requests | x | | `${{TO_TAG}}` | Defines until which tag the changelog did consider merged pull requests | x |
| `${{TO_TAG_DATE}}` | Defines the date at which the 'until' tag was created | x |
| `${{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 |
| `${{CHANGED_FILES}}` | The count of changed files. | | | `${{CHANGED_FILES}}` | The count of changed files. | |
| `${{ADDITIONS}}` | The count of code additions (lines). | | | `${{ADDITIONS}}` | The count of code additions (lines). | |
+30 -20
View File
@@ -14,11 +14,12 @@ it('Should have empty changelog (tags)', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v0.0.1', fromTag: { name: 'v0.0.1' },
toTag: 'v0.0.2', toTag: { name: 'v0.0.2' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -33,11 +34,12 @@ it('Should match generated changelog (tags)', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v0.0.1', fromTag: { name: 'v0.0.1'},
toTag: 'v0.0.3', toTag: { name: 'v0.0.3' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -60,11 +62,12 @@ it('Should match generated changelog (refs)', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3', fromTag: { name: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3' },
toTag: 'fa3788c8c4b3373ef8424ce3eb008a5cd07cc5aa', toTag: { name: 'fa3788c8c4b3373ef8424ce3eb008a5cd07cc5aa' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -95,11 +98,12 @@ it('Should match generated changelog and replace all occurrences (refs)', async
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3', fromTag: { name: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3' },
toTag: 'fa3788c8c4b3373ef8424ce3eb008a5cd07cc5aa', toTag: { name: 'fa3788c8c4b3373ef8424ce3eb008a5cd07cc5aa' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -132,11 +136,12 @@ it('Should match ordered ASC', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v0.3.0', fromTag: { name: 'v0.3.0' },
toTag: 'v0.5.0', toTag: { name: 'v0.5.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -156,11 +161,12 @@ it('Should match ordered DESC', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v0.3.0', fromTag: { name: 'v0.3.0' },
toTag: 'v0.5.0', toTag: { name: 'v0.5.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -180,11 +186,12 @@ it('Should match ordered by title ASC', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v0.3.0', fromTag: { name: 'v0.3.0' },
toTag: 'v0.5.0', toTag: { name: 'v0.5.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -204,11 +211,12 @@ it('Should match ordered by title DESC', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v0.3.0', fromTag: { name: 'v0.3.0' },
toTag: 'v0.5.0', toTag: { name: 'v0.5.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -228,11 +236,12 @@ it('Should ignore PRs not merged into develop branch', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v1.3.1', fromTag: { name: 'v1.3.1' },
toTag: 'v1.4.0', toTag: { name: 'v1.4.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -250,11 +259,12 @@ it('Should ignore PRs not merged into main branch', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v1.3.1', fromTag: { name: 'v1.3.1' },
toTag: 'v1.4.0', toTag: { name: 'v1.4.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
+73 -2
View File
@@ -17,6 +17,7 @@ it('Should match generated changelog (unspecified fromTag)', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -45,6 +46,7 @@ it('Should match generated changelog (unspecified tags)', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -70,6 +72,7 @@ it('Should use empty placeholder', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -96,6 +99,7 @@ it('Should fill empty placeholders', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -124,6 +128,7 @@ it('Should fill `template` placeholders', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -152,6 +157,7 @@ it('Should fill `template` placeholders, ignore', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -180,6 +186,7 @@ it('Uncategorized category', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -208,6 +215,7 @@ it('Verify commit based changelog', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
true, true,
configuration configuration
) )
@@ -236,6 +244,7 @@ it('Verify commit based changelog, with emoji categorisation', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
true, true,
configuration configuration
) )
@@ -264,6 +273,7 @@ it('Verify default inclusion of open PRs', async () => {
false, // failOnError false, // failOnError
false, // ignorePrePrelease false, // ignorePrePrelease
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // commitMode false, // commitMode
configuration // configuration configuration // configuration
) )
@@ -292,6 +302,7 @@ it('Verify custom categorisation of open PRs', async () => {
false, // failOnError false, // failOnError
false, // ignorePrePrelease false, // ignorePrePrelease
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // commitMode false, // commitMode
configuration // configuration configuration // configuration
) )
@@ -303,7 +314,7 @@ it('Verify custom categorisation of open PRs', async () => {
) )
}) })
it('Verify reviewers who approved are fetched', async () => { it('Verify reviewers who approved are fetched and also release information', async () => {
const configuration = resolveConfiguration( const configuration = resolveConfiguration(
'', '',
'configs_test/configuration_approvers.json' 'configs_test/configuration_approvers.json'
@@ -320,6 +331,7 @@ it('Verify reviewers who approved are fetched', async () => {
false, // failOnError false, // failOnError
false, // ignorePrePrelease false, // ignorePrePrelease
true, // enable to fetch reviewers true, // enable to fetch reviewers
true, // enable to fetch tag release information
false, // commitMode false, // commitMode
configuration // configuration configuration // configuration
) )
@@ -327,6 +339,65 @@ it('Verify reviewers who approved are fetched', async () => {
const changeLog = await releaseNotesBuilder.build() const changeLog = await releaseNotesBuilder.build()
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual( 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] --- gabrielpopa\n\n` `## 🚀 Features\n\n- A feature to be going to v2 (nr3) -- (#3) [merged] --- \n- New feature to keep open (nr5) -- (#7) [open] --- gabrielpopa\n\n\n\n0`
) )
})
it('Fetch release information', async () => {
const configuration = resolveConfiguration(
'',
'configs_test/configuration_approvers.json'
)
configuration.template = "${{FROM_TAG}}-${{FROM_TAG_DATE}}\n${{TO_TAG}}-${{TO_TAG_DATE}}\n${{DAYS_SINCE}}"
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
null, // token
'.', // repoPath
'mikepenz', // user
'release-changelog-builder-action-playground', // repo
'2.0.0', // fromTag
'3.0.0-a01', // toTag
true, // includeOpen
false, // failOnError
false, // ignorePrePrelease
false, // enable to fetch reviewers
true, // enable to fetch tag release information
false, // commitMode
configuration // configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(
`2.0.0-2022-04-08T07:52:40.000Z\n3.0.0-a01-2022-07-26T14:28:36.000Z\n109`
)
})
it('Fetch release information for non existing tag / release', async () => {
const configuration = resolveConfiguration(
'',
'configs_test/configuration_approvers.json'
)
configuration.template = "${{FROM_TAG}}-${{FROM_TAG_DATE}}\n${{TO_TAG}}-${{TO_TAG_DATE}}\n${{DAYS_SINCE}}"
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
null, // token
'.', // repoPath
'mikepenz', // user
'release-changelog-builder-action-playground', // repo
'2.0.0', // fromTag
'3.0.1', // toTag
true, // includeOpen
false, // failOnError
false, // ignorePrePrelease
false, // enable to fetch reviewers
true, // enable to fetch tag release information
false, // commitMode
configuration // configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(`- no changes`)
}) })
+41 -28
View File
@@ -134,11 +134,12 @@ it('Extract label from title, combined regex', async () => {
const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -163,11 +164,12 @@ it('Extract label from title and body, combined regex', async () => {
const resultChangelog = buildChangelog(DefaultDiffInfo, prs, { const resultChangelog = buildChangelog(DefaultDiffInfo, prs, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -194,11 +196,12 @@ it('Extract label from title, split regex', async () => {
const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -225,11 +228,12 @@ it('Extract label from title, match', async () => {
const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -251,11 +255,12 @@ it('Extract label from title, match multiple', async () => {
const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -278,11 +283,12 @@ it('Extract label from title, match multiple, custon non matching label', async
const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -392,11 +398,12 @@ it('Match multiple labels exhaustive for category', async () => {
const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration: customConfig configuration: customConfig
}) })
@@ -417,11 +424,12 @@ it('Deduplicate duplicated PRs', async () => {
const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration: customConfig configuration: customConfig
}) })
@@ -443,11 +451,12 @@ it('Deduplicate duplicated PRs DESC', async () => {
const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration: customConfig configuration: customConfig
}) })
@@ -475,11 +484,12 @@ it('Use empty_content for empty category', async () => {
const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration: customConfig configuration: customConfig
}) })
@@ -497,11 +507,12 @@ it('Commit SHA-1 in commitMode', async () => {
const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: true, commitMode: true,
configuration: customConfig configuration: customConfig
}) })
@@ -513,22 +524,23 @@ it('Commit SHA-1 in commitMode', async () => {
it('Release Diff', async () => { it('Release Diff', async () => {
const customConfig = Object.assign({}, DefaultConfiguration) const customConfig = Object.assign({}, DefaultConfiguration)
customConfig.template = "${{RELEASE_DIFF}}" customConfig.template = "${{RELEASE_DIFF}}\n${{DAYS_SINCE}}"
const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v2.8.0', fromTag: { name: 'v2.8.0' },
toTag: 'v2.8.1', toTag: { name: 'v2.8.1' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: true,
commitMode: true, commitMode: true,
configuration: customConfig configuration: customConfig
}) })
expect(resultChangelog).toStrictEqual( expect(resultChangelog).toStrictEqual(
`https://github.com/mikepenz/release-changelog-builder-action/compare/v2.8.0...v2.8.1` `https://github.com/mikepenz/release-changelog-builder-action/compare/v2.8.0...v2.8.1\n`
) )
}) })
@@ -557,11 +569,12 @@ it('Use exclude labels to not include a PR within a category.', async () => {
const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration: customConfig configuration: customConfig
}) })
+3
View File
@@ -29,6 +29,9 @@ inputs:
fetchReviewers: fetchReviewers:
description: 'Will enable fetching the users/reviewers who approved the PR' description: 'Will enable fetching the users/reviewers who approved the PR'
default: "false" default: "false"
fetchReleaseInformation:
description: 'Will enable fetching release information for the tags. E.g. creation date'
default: "false"
commitMode: commitMode:
description: 'Enables a `light` commit based mode. This mode generates changelogs based on the commits. Please note that this is not officially supported, and lacks a lot of features only possible with PRs.' description: 'Enables a `light` commit based mode. This mode generates changelogs based on the commits. Please note that this is not officially supported, and lacks a lot of features only possible with PRs.'
default: "false" default: "false"
+1 -1
View File
@@ -1,4 +1,4 @@
{ {
"template": "${{CHANGELOG}}", "template": "${{CHANGELOG}}\n\n${{DAYS_SINCE}}",
"pr_template": "- ${{TITLE}} -- (#${{NUMBER}}) [${{STATUS}}] ${{REVIEWERS}} --- ${{APPROVERS}}" "pr_template": "- ${{TITLE}} -- (#${{NUMBER}}) [${{STATUS}}] ${{REVIEWERS}} --- ${{APPROVERS}}"
} }
Generated Vendored
+85 -19
View File
@@ -307,6 +307,16 @@ class GitCommandManager {
return revListOutput.stdout.trim(); return revListOutput.stdout.trim();
}); });
} }
tagCreation(tagName) {
return __awaiter(this, void 0, void 0, function* () {
const creationDate = yield this.execGit([
'for-each-ref',
'--format="%(creatordate:rfc)"',
`refs/tags/${tagName}`
]);
return creationDate.stdout.trim().replace(/"/g, '');
});
}
static createCommandManager(workingDirectory) { static createCommandManager(workingDirectory) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const result = new GitCommandManager(); const result = new GitCommandManager();
@@ -417,8 +427,9 @@ function run() {
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 fetchReviewers = core.getInput('fetchReviewers') === 'true'; const fetchReviewers = core.getInput('fetchReviewers') === 'true';
const fetchReleaseInformation = core.getInput('fetchReleaseInformation') === '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, includeOpen, failOnError, ignorePreReleases, fetchReviewers, commitMode, configuration).build(); const result = yield new releaseNotesBuilder_1.ReleaseNotesBuilder(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen, failOnError, ignorePreReleases, fetchReviewers, fetchReleaseInformation, 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');
@@ -791,18 +802,18 @@ class ReleaseNotes {
getCommitHistory(octokit) { getCommitHistory(octokit) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const { owner, repo, fromTag, toTag, failOnError } = this.options; const { owner, repo, fromTag, toTag, failOnError } = this.options;
core.info(`️ Comparing ${owner}/${repo} - '${fromTag}...${toTag}'`); core.info(`️ Comparing ${owner}/${repo} - '${fromTag.name}...${toTag.name}'`);
const commitsApi = new commits_1.Commits(octokit); const commitsApi = new commits_1.Commits(octokit);
let diffInfo; let diffInfo;
try { try {
diffInfo = yield commitsApi.getDiff(owner, repo, fromTag, toTag); diffInfo = yield commitsApi.getDiff(owner, repo, fromTag.name, toTag.name);
} }
catch (error) { catch (error) {
(0, utils_1.failOrError)(`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, failOnError); (0, utils_1.failOrError)(`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, failOnError);
return commits_1.DefaultDiffInfo; return commits_1.DefaultDiffInfo;
} }
if (diffInfo.commitInfo.length === 0) { if (diffInfo.commitInfo.length === 0) {
core.warning(`⚠️ No commits found between - ${fromTag}...${toTag}`); core.warning(`⚠️ No commits found between - ${fromTag.name}...${toTag.name}`);
return commits_1.DefaultDiffInfo; return commits_1.DefaultDiffInfo;
} }
return diffInfo; return diffInfo;
@@ -876,6 +887,9 @@ class ReleaseNotes {
} }
} }
} }
else {
core.debug(`️ Fetching reviewers was disabled`);
}
return [diffInfo, finalPrs]; return [diffInfo, finalPrs];
}); });
} }
@@ -965,7 +979,7 @@ const releaseNotes_1 = __nccwpck_require__(5882);
const tags_1 = __nccwpck_require__(7532); const tags_1 = __nccwpck_require__(7532);
const utils_1 = __nccwpck_require__(918); const utils_1 = __nccwpck_require__(918);
class ReleaseNotesBuilder { class ReleaseNotesBuilder {
constructor(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen = false, failOnError, ignorePreReleases, fetchReviewers = false, commitMode, configuration) { constructor(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen = false, failOnError, ignorePreReleases, fetchReviewers = false, fetchReleaseInformation = false, commitMode, configuration) {
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
this.token = token; this.token = token;
this.repositoryPath = repositoryPath; this.repositoryPath = repositoryPath;
@@ -977,11 +991,11 @@ class ReleaseNotesBuilder {
this.failOnError = failOnError; this.failOnError = failOnError;
this.ignorePreReleases = ignorePreReleases; this.ignorePreReleases = ignorePreReleases;
this.fetchReviewers = fetchReviewers; this.fetchReviewers = fetchReviewers;
this.fetchReleaseInformation = fetchReleaseInformation;
this.commitMode = commitMode; this.commitMode = commitMode;
this.configuration = configuration; this.configuration = configuration;
} }
build() { build() {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
if (!this.owner) { if (!this.owner) {
(0, utils_1.failOrError)(`💥 Missing or couldn't resolve 'owner'`, this.failOnError); (0, utils_1.failOrError)(`💥 Missing or couldn't resolve 'owner'`, this.failOnError);
@@ -1010,33 +1024,41 @@ class ReleaseNotesBuilder {
const tagsApi = new tags_1.Tags(octokit); const tagsApi = new tags_1.Tags(octokit);
const tagRange = yield tagsApi.retrieveRange(this.repositoryPath, this.owner, this.repo, this.fromTag, this.toTag, this.ignorePreReleases, this.configuration.max_tags_to_fetch || const tagRange = yield tagsApi.retrieveRange(this.repositoryPath, this.owner, this.repo, this.fromTag, this.toTag, this.ignorePreReleases, this.configuration.max_tags_to_fetch ||
configuration_1.DefaultConfiguration.max_tags_to_fetch, this.configuration.tag_resolver || configuration_1.DefaultConfiguration.tag_resolver); configuration_1.DefaultConfiguration.max_tags_to_fetch, this.configuration.tag_resolver || configuration_1.DefaultConfiguration.tag_resolver);
const thisTag = (_a = tagRange.to) === null || _a === void 0 ? void 0 : _a.name; let thisTag = tagRange.to;
if (!thisTag) { if (!thisTag) {
(0, utils_1.failOrError)(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError); (0, utils_1.failOrError)(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError);
return null; return null;
} }
else { else {
this.toTag = thisTag; core.setOutput('toTag', thisTag.name);
core.setOutput('toTag', thisTag); core.debug(`Resolved 'toTag' as ${thisTag.name}`);
core.debug(`Resolved 'toTag' as ${thisTag}`);
} }
const previousTag = (_b = tagRange.from) === null || _b === void 0 ? void 0 : _b.name; let previousTag = tagRange.from;
if (previousTag == null) { if (previousTag == null) {
(0, utils_1.failOrError)(`💥 Unable to retrieve previous tag given ${this.toTag}`, this.failOnError); (0, utils_1.failOrError)(`💥 Unable to retrieve previous tag given ${this.toTag}`, this.failOnError);
return null; return null;
} }
this.fromTag = previousTag; core.setOutput('fromTag', previousTag.name);
core.setOutput('fromTag', previousTag); core.debug(`fromTag resolved via previousTag as: ${previousTag.name}`);
core.debug(`fromTag resolved via previousTag as: ${previousTag}`); if (this.fetchReleaseInformation) {
// load release information from the GitHub API
core.info(`️ Fetching release information was enabled`);
thisTag = yield tagsApi.fillTagInformation(this.repositoryPath, this.owner, this.repo, thisTag);
previousTag = yield tagsApi.fillTagInformation(this.repositoryPath, this.owner, this.repo, previousTag);
}
else {
core.debug(`️ Fetching release information was disabled`);
}
core.endGroup(); core.endGroup();
const options = { const options = {
owner: this.owner, owner: this.owner,
repo: this.repo, repo: this.repo,
fromTag: this.fromTag, fromTag: previousTag,
toTag: this.toTag, toTag: thisTag,
includeOpen: this.includeOpen, includeOpen: this.includeOpen,
failOnError: this.failOnError, failOnError: this.failOnError,
fetchReviewers: this.fetchReviewers, fetchReviewers: this.fetchReviewers,
fetchReleaseInformation: this.fetchReleaseInformation,
commitMode: this.commitMode, commitMode: this.commitMode,
configuration: this.configuration configuration: this.configuration
}; };
@@ -1094,6 +1116,9 @@ var __asyncValues = (this && this.__asyncValues) || function (o) {
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
}; };
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.sortTags = exports.filterTags = exports.Tags = void 0; exports.sortTags = exports.filterTags = exports.Tags = void 0;
const core = __importStar(__nccwpck_require__(2186)); const core = __importStar(__nccwpck_require__(2186));
@@ -1102,6 +1127,7 @@ const semver = __importStar(__nccwpck_require__(1383));
const semver_1 = __nccwpck_require__(1383); const semver_1 = __nccwpck_require__(1383);
const gitHelper_1 = __nccwpck_require__(353); const gitHelper_1 = __nccwpck_require__(353);
const transform_1 = __nccwpck_require__(1644); const transform_1 = __nccwpck_require__(1644);
const moment_1 = __importDefault(__nccwpck_require__(9623));
class Tags { class Tags {
constructor(octokit) { constructor(octokit) {
this.octokit = octokit; this.octokit = octokit;
@@ -1143,6 +1169,35 @@ class Tags {
return tagsInfo; return tagsInfo;
}); });
} }
fillTagInformation(repositoryPath, owner, repo, tagInfo) {
return __awaiter(this, void 0, void 0, function* () {
const options = this.octokit.repos.getReleaseByTag.endpoint.merge({
owner,
repo,
tag: tagInfo.name
});
try {
const response = yield this.octokit.request(options);
const release = response.data;
tagInfo.date = (0, moment_1.default)(release.created_at);
core.info(`️ Retrieved information about the release associated with ${tagInfo.name} from the GitHub API`);
}
catch (error) {
core.info(`⚠️ No release information found for ${tagInfo.name}, trying to retrieve tag creation time as fallback.`);
const gitHelper = yield (0, gitHelper_1.createCommandManager)(repositoryPath);
const creationTimeString = yield gitHelper.tagCreation(tagInfo.name);
const creationTime = (0, moment_1.default)(creationTimeString);
if (creationTimeString !== null && creationTime.isValid()) {
tagInfo.date = creationTime;
core.info(`️ Resolved tag creation time (${creationTimeString}) from 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}`);
}
else {
core.info(`⚠️ Could not retrieve tag creation time via git cli 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}'`);
}
}
return tagInfo;
});
}
findPredecessorTag(sortedTags, repositoryPath, tag, ignorePreReleases) { findPredecessorTag(sortedTags, repositoryPath, tag, ignorePreReleases) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const tags = sortedTags; const tags = sortedTags;
@@ -1601,13 +1656,24 @@ function buildChangelog(diffInfo, prs, options) {
} }
exports.buildChangelog = buildChangelog; exports.buildChangelog = buildChangelog;
function fillAdditionalPlaceholders(text, options) { function fillAdditionalPlaceholders(text, options) {
var _a, _b;
let transformed = text; let transformed = text;
// repository placeholders // repository placeholders
transformed = transformed.replace(/\${{OWNER}}/g, options.owner); transformed = transformed.replace(/\${{OWNER}}/g, options.owner);
transformed = transformed.replace(/\${{REPO}}/g, options.repo); transformed = transformed.replace(/\${{REPO}}/g, options.repo);
transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag); transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag.name);
transformed = transformed.replace(/\${{TO_TAG}}/g, options.toTag); transformed = transformed.replace(/\${{FROM_TAG_DATE}}/g, ((_a = options.fromTag.date) === null || _a === void 0 ? void 0 : _a.toISOString()) || '');
transformed = transformed.replace(/\${{RELEASE_DIFF}}/g, `https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag}...${options.toTag}`); transformed = transformed.replace(/\${{TO_TAG}}/g, options.toTag.name);
transformed = transformed.replace(/\${{TO_TAG_DATE}}/g, ((_b = options.toTag.date) === null || _b === void 0 ? void 0 : _b.toISOString()) || '');
const fromDate = options.fromTag.date;
const toDate = options.toTag.date;
if (fromDate !== undefined && toDate !== undefined) {
transformed = transformed.replace(/\${{DAYS_SINCE}}/g, toDate.diff(fromDate, 'days').toString() || '');
}
else {
transformed = transformed.replace(/\${{DAYS_SINCE}}/g, '');
}
transformed = transformed.replace(/\${{RELEASE_DIFF}}/g, `https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag.name}...${options.toTag.name}`);
return transformed; return transformed;
} }
exports.fillAdditionalPlaceholders = fillAdditionalPlaceholders; exports.fillAdditionalPlaceholders = fillAdditionalPlaceholders;
Generated Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
+9
View File
@@ -44,6 +44,15 @@ class GitCommandManager {
return revListOutput.stdout.trim() return revListOutput.stdout.trim()
} }
async tagCreation(tagName: string): Promise<string> {
const creationDate = await this.execGit([
'for-each-ref',
'--format="%(creatordate:rfc)"',
`refs/tags/${tagName}`
])
return creationDate.stdout.trim().replace(/"/g, '')
}
static async createCommandManager( static async createCommandManager(
workingDirectory: string workingDirectory: string
): Promise<GitCommandManager> { ): Promise<GitCommandManager> {
+3
View File
@@ -36,6 +36,8 @@ async function run(): Promise<void> {
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 fetchReviewers = core.getInput('fetchReviewers') === 'true' const fetchReviewers = core.getInput('fetchReviewers') === 'true'
const fetchReleaseInformation =
core.getInput('fetchReleaseInformation') === 'true'
const commitMode = core.getInput('commitMode') === 'true' const commitMode = core.getInput('commitMode') === 'true'
const result = await new ReleaseNotesBuilder( const result = await new ReleaseNotesBuilder(
@@ -50,6 +52,7 @@ async function run(): Promise<void> {
failOnError, failOnError,
ignorePreReleases, ignorePreReleases,
fetchReviewers, fetchReviewers,
fetchReleaseInformation,
commitMode, commitMode,
configuration configuration
).build() ).build()
+13 -5
View File
@@ -5,15 +5,17 @@ import {PullRequestInfo, PullRequests} from './pullRequests'
import {Octokit} from '@octokit/rest' import {Octokit} from '@octokit/rest'
import {buildChangelog, fillAdditionalPlaceholders} from './transform' import {buildChangelog, fillAdditionalPlaceholders} from './transform'
import {failOrError} from './utils' import {failOrError} from './utils'
import {TagInfo} from './tags'
export interface ReleaseNotesOptions { export interface ReleaseNotesOptions {
owner: string // the owner of the repository owner: string // the owner of the repository
repo: string // the repository repo: string // the repository
fromTag: string // the tag/ref to start from fromTag: TagInfo // the tag/ref to start from
toTag: string // the tag/ref up to toTag: TagInfo // the tag/ref up to
includeOpen: boolean // defines if we should also fetch open pull requests 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
fetchReviewers: boolean // defines if the action should fetch the reviewers for PRs - approved reviewers are not included in the default PR listing fetchReviewers: boolean // defines if the action should fetch the reviewers for PRs - approved reviewers are not included in the default PR listing
fetchReleaseInformation: boolean // defines if the action should fetch the release information for the from and to tag - e.g. the creation date for the associated release
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`
} }
@@ -78,12 +80,14 @@ export class ReleaseNotes {
private async getCommitHistory(octokit: Octokit): Promise<DiffInfo> { private async getCommitHistory(octokit: Octokit): Promise<DiffInfo> {
const {owner, repo, fromTag, toTag, failOnError} = this.options const {owner, repo, fromTag, toTag, failOnError} = this.options
core.info(`️ Comparing ${owner}/${repo} - '${fromTag}...${toTag}'`) core.info(
`️ Comparing ${owner}/${repo} - '${fromTag.name}...${toTag.name}'`
)
const commitsApi = new Commits(octokit) const commitsApi = new Commits(octokit)
let diffInfo: DiffInfo let diffInfo: DiffInfo
try { try {
diffInfo = await commitsApi.getDiff(owner, repo, fromTag, toTag) diffInfo = await commitsApi.getDiff(owner, repo, fromTag.name, toTag.name)
} catch (error) { } catch (error) {
failOrError( failOrError(
`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, `💥 Failed to retrieve - Invalid tag? - Because of: ${error}`,
@@ -92,7 +96,9 @@ export class ReleaseNotes {
return DefaultDiffInfo return DefaultDiffInfo
} }
if (diffInfo.commitInfo.length === 0) { if (diffInfo.commitInfo.length === 0) {
core.warning(`⚠️ No commits found between - ${fromTag}...${toTag}`) core.warning(
`⚠️ No commits found between - ${fromTag.name}...${toTag.name}`
)
return DefaultDiffInfo return DefaultDiffInfo
} }
@@ -212,6 +218,8 @@ export class ReleaseNotes {
) )
} }
} }
} else {
core.debug(`️ Fetching reviewers was disabled`)
} }
return [diffInfo, finalPrs] return [diffInfo, finalPrs]
+30 -10
View File
@@ -18,6 +18,7 @@ export class ReleaseNotesBuilder {
private failOnError: boolean, private failOnError: boolean,
private ignorePreReleases: boolean, private ignorePreReleases: boolean,
private fetchReviewers: boolean = false, private fetchReviewers: boolean = false,
private fetchReleaseInformation: boolean = false,
private commitMode: boolean, private commitMode: boolean,
private configuration: Configuration private configuration: Configuration
) {} ) {}
@@ -61,17 +62,16 @@ export class ReleaseNotesBuilder {
this.configuration.tag_resolver || DefaultConfiguration.tag_resolver this.configuration.tag_resolver || DefaultConfiguration.tag_resolver
) )
const thisTag = tagRange.to?.name let thisTag = tagRange.to
if (!thisTag) { if (!thisTag) {
failOrError(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError) failOrError(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError)
return null return null
} else { } else {
this.toTag = thisTag core.setOutput('toTag', thisTag.name)
core.setOutput('toTag', thisTag) core.debug(`Resolved 'toTag' as ${thisTag.name}`)
core.debug(`Resolved 'toTag' as ${thisTag}`)
} }
const previousTag = tagRange.from?.name let previousTag = tagRange.from
if (previousTag == null) { if (previousTag == null) {
failOrError( failOrError(
`💥 Unable to retrieve previous tag given ${this.toTag}`, `💥 Unable to retrieve previous tag given ${this.toTag}`,
@@ -79,19 +79,39 @@ export class ReleaseNotesBuilder {
) )
return null return null
} }
this.fromTag = previousTag core.setOutput('fromTag', previousTag.name)
core.setOutput('fromTag', previousTag) core.debug(`fromTag resolved via previousTag as: ${previousTag.name}`)
core.debug(`fromTag resolved via previousTag as: ${previousTag}`)
if (this.fetchReleaseInformation) {
// load release information from the GitHub API
core.info(`️ Fetching release information was enabled`)
thisTag = await tagsApi.fillTagInformation(
this.repositoryPath,
this.owner,
this.repo,
thisTag
)
previousTag = await tagsApi.fillTagInformation(
this.repositoryPath,
this.owner,
this.repo,
previousTag
)
} else {
core.debug(`️ Fetching release information was disabled`)
}
core.endGroup() core.endGroup()
const options = { const options = {
owner: this.owner, owner: this.owner,
repo: this.repo, repo: this.repo,
fromTag: this.fromTag, fromTag: previousTag,
toTag: this.toTag, toTag: thisTag,
includeOpen: this.includeOpen, includeOpen: this.includeOpen,
failOnError: this.failOnError, failOnError: this.failOnError,
fetchReviewers: this.fetchReviewers, fetchReviewers: this.fetchReviewers,
fetchReleaseInformation: this.fetchReleaseInformation,
commitMode: this.commitMode, commitMode: this.commitMode,
configuration: this.configuration configuration: this.configuration
} }
+46 -1
View File
@@ -6,6 +6,7 @@ import {SemVer} from 'semver'
import {TagResolver} from './configuration' import {TagResolver} from './configuration'
import {createCommandManager} from './gitHelper' import {createCommandManager} from './gitHelper'
import {RegexTransformer, validateTransformer} from './transform' import {RegexTransformer, validateTransformer} from './transform'
import moment from 'moment'
export interface TagResult { export interface TagResult {
from: TagInfo | null from: TagInfo | null
@@ -14,7 +15,8 @@ export interface TagResult {
export interface TagInfo { export interface TagInfo {
name: string name: string
commit: string commit?: string
date?: moment.Moment
} }
export interface SortableTagInfo extends TagInfo { export interface SortableTagInfo extends TagInfo {
@@ -61,6 +63,49 @@ export class Tags {
return tagsInfo return tagsInfo
} }
async fillTagInformation(
repositoryPath: string,
owner: string,
repo: string,
tagInfo: TagInfo
): Promise<TagInfo> {
const options = this.octokit.repos.getReleaseByTag.endpoint.merge({
owner,
repo,
tag: tagInfo.name
})
try {
const response = await this.octokit.request(options)
type ReleaseInformation =
RestEndpointMethodTypes['repos']['getReleaseByTag']['response']['data']
const release: ReleaseInformation = response.data as ReleaseInformation
tagInfo.date = moment(release.created_at)
core.info(
`️ Retrieved information about the release associated with ${tagInfo.name} from the GitHub API`
)
} catch (error) {
core.info(
`⚠️ No release information found for ${tagInfo.name}, trying to retrieve tag creation time as fallback.`
)
const gitHelper = await createCommandManager(repositoryPath)
const creationTimeString = await gitHelper.tagCreation(tagInfo.name)
const creationTime = moment(creationTimeString)
if (creationTimeString !== null && creationTime.isValid()) {
tagInfo.date = creationTime
core.info(
`️ Resolved tag creation time (${creationTimeString}) from 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}`
)
} else {
core.info(
`⚠️ Could not retrieve tag creation time via git cli 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}'`
)
}
}
return tagInfo
}
async findPredecessorTag( async findPredecessorTag(
sortedTags: TagInfo[], sortedTags: TagInfo[],
repositoryPath: string, repositoryPath: string,
+21 -3
View File
@@ -312,11 +312,29 @@ export function fillAdditionalPlaceholders(
// repository placeholders // repository placeholders
transformed = transformed.replace(/\${{OWNER}}/g, options.owner) transformed = transformed.replace(/\${{OWNER}}/g, options.owner)
transformed = transformed.replace(/\${{REPO}}/g, options.repo) transformed = transformed.replace(/\${{REPO}}/g, options.repo)
transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag) transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag.name)
transformed = transformed.replace(/\${{TO_TAG}}/g, options.toTag) transformed = transformed.replace(
/\${{FROM_TAG_DATE}}/g,
options.fromTag.date?.toISOString() || ''
)
transformed = transformed.replace(/\${{TO_TAG}}/g, options.toTag.name)
transformed = transformed.replace(
/\${{TO_TAG_DATE}}/g,
options.toTag.date?.toISOString() || ''
)
const fromDate = options.fromTag.date
const toDate = options.toTag.date
if (fromDate !== undefined && toDate !== undefined) {
transformed = transformed.replace(
/\${{DAYS_SINCE}}/g,
toDate.diff(fromDate, 'days').toString() || ''
)
} else {
transformed = transformed.replace(/\${{DAYS_SINCE}}/g, '')
}
transformed = transformed.replace( transformed = transformed.replace(
/\${{RELEASE_DIFF}}/g, /\${{RELEASE_DIFF}}/g,
`https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag}...${options.toTag}` `https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag.name}...${options.toTag.name}`
) )
return transformed return transformed
} }