Merge pull request #1123 from mikepenz/feature/restructure_action
Refactor action and offer delayed changelog generation
This commit is contained in:
@@ -113,6 +113,19 @@ jobs:
|
|||||||
run: echo "CHANGELOG"
|
run: echo "CHANGELOG"
|
||||||
|
|
||||||
# Showcases the capability to generate the changelog for an external repository provided
|
# Showcases the capability to generate the changelog for an external repository provided
|
||||||
|
# Showcase ability to only fetch data first, and then continue with exported data later
|
||||||
|
- name: "External Repo Configuration Collect Report"
|
||||||
|
id: external_changelog_collect
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
owner: "mikepenz"
|
||||||
|
repo: "MaterialDrawer"
|
||||||
|
fromTag: "v8.1.0"
|
||||||
|
toTag: "v8.1.6"
|
||||||
|
token: ${{ secrets.PERSONAL_TOKEN }}
|
||||||
|
exportCollected: true
|
||||||
|
exportOnly: true
|
||||||
|
|
||||||
- name: "External Repo Configuration"
|
- name: "External Repo Configuration"
|
||||||
id: external_changelog
|
id: external_changelog
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -120,14 +133,35 @@ jobs:
|
|||||||
configuration: "configs/configuration_complex.json"
|
configuration: "configs/configuration_complex.json"
|
||||||
owner: "mikepenz"
|
owner: "mikepenz"
|
||||||
repo: "MaterialDrawer"
|
repo: "MaterialDrawer"
|
||||||
fromTag: "v8.1.0"
|
|
||||||
toTag: "v8.1.6"
|
- name: "External Repo Configuration Second"
|
||||||
token: ${{ secrets.PERSONAL_TOKEN }}
|
id: external_changelog_second
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
configurationJson: |
|
||||||
|
{
|
||||||
|
"template": "#{{CHANGELOG}}",
|
||||||
|
"pr_template": "PR: ##{{NUMBER}}",
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"title": "## Everything",
|
||||||
|
"labels": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
owner: "mikepenz"
|
||||||
|
repo: "MaterialDrawer"
|
||||||
|
|
||||||
- name: Echo External Repo Configuration Changelog
|
- name: Echo External Repo Configuration Changelog
|
||||||
env:
|
env:
|
||||||
CHANGELOG: ${{ steps.external_changelog.outputs.changelog }}
|
CHANGELOG: ${{ steps.external_changelog.outputs.changelog }}
|
||||||
run: echo "$CHANGELOG"
|
CHANGELOG_SECOND: ${{ steps.external_changelog_second.outputs.changelog }}
|
||||||
|
run: |
|
||||||
|
echo "First:"
|
||||||
|
echo "$CHANGELOG"
|
||||||
|
|
||||||
|
echo "Second:"
|
||||||
|
echo "$CHANGELOG_SECOND"
|
||||||
|
|
||||||
release:
|
release:
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ it('Should match generated changelog (unspecified fromTag)', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
false, // enable to fetch tag release information
|
false, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
false,
|
false, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -49,7 +51,9 @@ it('Should match generated changelog (unspecified tags)', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
false, // enable to fetch tag release information
|
false, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
false,
|
false, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -74,7 +78,9 @@ it('Should use empty placeholder', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
false, // enable to fetch tag release information
|
false, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
false,
|
false, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -99,7 +105,9 @@ it('Should fill empty placeholders', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
false, // enable to fetch tag release information
|
false, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
false,
|
false, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -126,7 +134,9 @@ it('Should fill `template` placeholders', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
false, // enable to fetch tag release information
|
false, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
false,
|
false, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -153,7 +163,9 @@ it('Should fill `template` placeholders, ignore', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
false, // enable to fetch tag release information
|
false, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
false,
|
false, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -180,7 +192,9 @@ it('Uncategorized category', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
false, // enable to fetch tag release information
|
false, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
false,
|
false, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -207,7 +221,9 @@ it('Verify commit based changelog', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
false, // enable to fetch tag release information
|
false, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
true,
|
true, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -234,7 +250,9 @@ it('Verify commit based changelog, with emoji categorisation', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
false, // enable to fetch tag release information
|
false, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
true,
|
true, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -261,7 +279,9 @@ it('Verify default inclusion of open PRs', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
false, // enable to fetch tag release information
|
false, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
false, // commitMode
|
false, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration // configuration
|
configuration // configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -288,7 +308,9 @@ it('Verify custom categorisation of open PRs', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
false, // enable to fetch tag release information
|
false, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
false, // commitMode
|
false, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration // configuration
|
configuration // configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -315,7 +337,9 @@ it('Verify reviewers who approved are fetched and also release information', asy
|
|||||||
true, // enable to fetch reviewers
|
true, // enable to fetch reviewers
|
||||||
true, // enable to fetch tag release information
|
true, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
false, // commitMode
|
false, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration // configuration
|
configuration // configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -343,7 +367,9 @@ it('Fetch release information', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
true, // enable to fetch tag release information
|
true, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
false, // commitMode
|
false, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration // configuration
|
configuration // configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -369,7 +395,9 @@ it('Fetch release information for non existing tag / release', async () => {
|
|||||||
false, // enable to fetch reviewers
|
false, // enable to fetch reviewers
|
||||||
true, // enable to fetch tag release information
|
true, // enable to fetch tag release information
|
||||||
false, // enable to fetch reviews
|
false, // enable to fetch reviews
|
||||||
false, // commitMode
|
false, // enable commitMode
|
||||||
|
false, // enable exportCollected
|
||||||
|
false, // enable exportOnly
|
||||||
configuration // configuration
|
configuration // configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {ReleaseNotes} from '../src/releaseNotes'
|
|
||||||
import {mergeConfiguration, resolveConfiguration} from '../src/utils'
|
import {mergeConfiguration, resolveConfiguration} from '../src/utils'
|
||||||
|
import {pullData} from '../src/releaseNotesBuilder'
|
||||||
import {Octokit} from '@octokit/rest'
|
import {Octokit} from '@octokit/rest'
|
||||||
|
import { buildChangelog } from '../src/transform'
|
||||||
|
|
||||||
jest.setTimeout(180000)
|
jest.setTimeout(180000)
|
||||||
|
|
||||||
@@ -11,7 +12,8 @@ const octokit = new Octokit({
|
|||||||
|
|
||||||
it('Should have empty changelog (tags)', async () => {
|
it('Should have empty changelog (tags)', async () => {
|
||||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs/configuration.json'))
|
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs/configuration.json'))
|
||||||
const releaseNotes = new ReleaseNotes(octokit, {
|
|
||||||
|
const data = await pullData(octokit, {
|
||||||
owner: 'mikepenz',
|
owner: 'mikepenz',
|
||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: {name: 'v0.0.1'},
|
fromTag: {name: 'v0.0.1'},
|
||||||
@@ -23,16 +25,16 @@ it('Should have empty changelog (tags)', async () => {
|
|||||||
fetchReviews: false,
|
fetchReviews: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
})
|
}, false, false)
|
||||||
|
|
||||||
const changeLog = await releaseNotes.pull()
|
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||||
console.log(changeLog)
|
console.log(changeLog)
|
||||||
expect(changeLog).toStrictEqual('- no changes')
|
expect(changeLog).toStrictEqual('- no changes')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should match generated changelog (tags)', async () => {
|
it('Should match generated changelog (tags)', async () => {
|
||||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs/configuration.json'))
|
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs/configuration.json'))
|
||||||
const releaseNotes = new ReleaseNotes(octokit, {
|
const data = await pullData(octokit, {
|
||||||
owner: 'mikepenz',
|
owner: 'mikepenz',
|
||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: {name: 'v0.0.1'},
|
fromTag: {name: 'v0.0.1'},
|
||||||
@@ -44,9 +46,9 @@ it('Should match generated changelog (tags)', async () => {
|
|||||||
fetchReviews: false,
|
fetchReviews: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
})
|
}, false, false)
|
||||||
|
|
||||||
const changeLog = await releaseNotes.pull()
|
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||||
console.log(changeLog)
|
console.log(changeLog)
|
||||||
expect(changeLog).toStrictEqual(`## 🧪 Tests
|
expect(changeLog).toStrictEqual(`## 🧪 Tests
|
||||||
|
|
||||||
@@ -58,7 +60,7 @@ it('Should match generated changelog (tags)', async () => {
|
|||||||
|
|
||||||
it('Should match generated changelog (refs)', async () => {
|
it('Should match generated changelog (refs)', async () => {
|
||||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_all_placeholders.json'))
|
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_all_placeholders.json'))
|
||||||
const releaseNotes = new ReleaseNotes(octokit, {
|
const data = await pullData(octokit, {
|
||||||
owner: 'mikepenz',
|
owner: 'mikepenz',
|
||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: {name: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3'},
|
fromTag: {name: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3'},
|
||||||
@@ -70,9 +72,9 @@ it('Should match generated changelog (refs)', async () => {
|
|||||||
fetchReviews: false,
|
fetchReviews: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
})
|
}, false, false)
|
||||||
|
|
||||||
const changeLog = await releaseNotes.pull()
|
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||||
console.log(changeLog)
|
console.log(changeLog)
|
||||||
expect(changeLog).toStrictEqual(`## 🧪 Tests
|
expect(changeLog).toStrictEqual(`## 🧪 Tests
|
||||||
|
|
||||||
@@ -92,7 +94,7 @@ nhoelzl
|
|||||||
|
|
||||||
it('Should match generated changelog and replace all occurrences (refs)', async () => {
|
it('Should match generated changelog and replace all occurrences (refs)', async () => {
|
||||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_replace_all_placeholders.json'))
|
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_replace_all_placeholders.json'))
|
||||||
const releaseNotes = new ReleaseNotes(octokit, {
|
const data = await pullData(octokit, {
|
||||||
owner: 'mikepenz',
|
owner: 'mikepenz',
|
||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: {name: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3'},
|
fromTag: {name: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3'},
|
||||||
@@ -104,9 +106,9 @@ it('Should match generated changelog and replace all occurrences (refs)', async
|
|||||||
fetchReviews: false,
|
fetchReviews: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
})
|
}, false, false)
|
||||||
|
|
||||||
const changeLog = await releaseNotes.pull()
|
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||||
console.log(changeLog)
|
console.log(changeLog)
|
||||||
expect(changeLog).toStrictEqual(`## 🧪 Tests
|
expect(changeLog).toStrictEqual(`## 🧪 Tests
|
||||||
|
|
||||||
@@ -128,7 +130,7 @@ nhoelzl
|
|||||||
|
|
||||||
it('Should match ordered ASC', async () => {
|
it('Should match ordered ASC', async () => {
|
||||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_asc.json'))
|
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_asc.json'))
|
||||||
const releaseNotes = new ReleaseNotes(octokit, {
|
const data = await pullData(octokit, {
|
||||||
owner: 'mikepenz',
|
owner: 'mikepenz',
|
||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: {name: 'v0.3.0'},
|
fromTag: {name: 'v0.3.0'},
|
||||||
@@ -140,16 +142,16 @@ it('Should match ordered ASC', async () => {
|
|||||||
fetchReviews: false,
|
fetchReviews: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
})
|
}, false, false)
|
||||||
|
|
||||||
const changeLog = await releaseNotes.pull()
|
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||||
console.log(changeLog)
|
console.log(changeLog)
|
||||||
expect(changeLog).toStrictEqual(`## 🚀 Features\n\n22\n24\n25\n26\n28\n\n## 🐛 Fixes\n\n23\n\n`)
|
expect(changeLog).toStrictEqual(`## 🚀 Features\n\n22\n24\n25\n26\n28\n\n## 🐛 Fixes\n\n23\n\n`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should match ordered DESC', async () => {
|
it('Should match ordered DESC', async () => {
|
||||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_desc.json'))
|
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_desc.json'))
|
||||||
const releaseNotes = new ReleaseNotes(octokit, {
|
const data = await pullData(octokit, {
|
||||||
owner: 'mikepenz',
|
owner: 'mikepenz',
|
||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: {name: 'v0.3.0'},
|
fromTag: {name: 'v0.3.0'},
|
||||||
@@ -161,16 +163,16 @@ it('Should match ordered DESC', async () => {
|
|||||||
fetchReviews: false,
|
fetchReviews: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
})
|
}, false, false)
|
||||||
|
|
||||||
const changeLog = await releaseNotes.pull()
|
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||||
console.log(changeLog)
|
console.log(changeLog)
|
||||||
expect(changeLog).toStrictEqual(`## 🚀 Features\n\n28\n26\n25\n24\n22\n\n## 🐛 Fixes\n\n23\n\n`)
|
expect(changeLog).toStrictEqual(`## 🚀 Features\n\n28\n26\n25\n24\n22\n\n## 🐛 Fixes\n\n23\n\n`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should match ordered by title ASC', async () => {
|
it('Should match ordered by title ASC', async () => {
|
||||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_sort_title_asc.json'))
|
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_sort_title_asc.json'))
|
||||||
const releaseNotes = new ReleaseNotes(octokit, {
|
const data = await pullData(octokit, {
|
||||||
owner: 'mikepenz',
|
owner: 'mikepenz',
|
||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: {name: 'v0.3.0'},
|
fromTag: {name: 'v0.3.0'},
|
||||||
@@ -182,9 +184,9 @@ it('Should match ordered by title ASC', async () => {
|
|||||||
fetchReviews: false,
|
fetchReviews: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
})
|
}, false, false)
|
||||||
|
|
||||||
const changeLog = await releaseNotes.pull()
|
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||||
console.log(changeLog)
|
console.log(changeLog)
|
||||||
expect(changeLog).toStrictEqual(
|
expect(changeLog).toStrictEqual(
|
||||||
`## 🚀 Features\n\nEnhanced action logs\nImprove README\nImproved configuration failure handling\nImproved defaults if no configuration is provided\nIntroduce additional placeholders [milestone, labels, assignees, reviewers]\n\n## 🐛 Fixes\n\nImproved handling for non existing tags\n\n`
|
`## 🚀 Features\n\nEnhanced action logs\nImprove README\nImproved configuration failure handling\nImproved defaults if no configuration is provided\nIntroduce additional placeholders [milestone, labels, assignees, reviewers]\n\n## 🐛 Fixes\n\nImproved handling for non existing tags\n\n`
|
||||||
@@ -193,7 +195,7 @@ it('Should match ordered by title ASC', async () => {
|
|||||||
|
|
||||||
it('Should match ordered by title DESC', async () => {
|
it('Should match ordered by title DESC', async () => {
|
||||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_sort_title_desc.json'))
|
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_sort_title_desc.json'))
|
||||||
const releaseNotes = new ReleaseNotes(octokit, {
|
const data = await pullData(octokit, {
|
||||||
owner: 'mikepenz',
|
owner: 'mikepenz',
|
||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: {name: 'v0.3.0'},
|
fromTag: {name: 'v0.3.0'},
|
||||||
@@ -205,9 +207,9 @@ it('Should match ordered by title DESC', async () => {
|
|||||||
fetchReviews: false,
|
fetchReviews: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
})
|
}, false, false)
|
||||||
|
|
||||||
const changeLog = await releaseNotes.pull()
|
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||||
console.log(changeLog)
|
console.log(changeLog)
|
||||||
expect(changeLog).toStrictEqual(
|
expect(changeLog).toStrictEqual(
|
||||||
`## 🚀 Features\n\nIntroduce additional placeholders [milestone, labels, assignees, reviewers]\nImproved defaults if no configuration is provided\nImproved configuration failure handling\nImprove README\nEnhanced action logs\n\n## 🐛 Fixes\n\nImproved handling for non existing tags\n\n`
|
`## 🚀 Features\n\nIntroduce additional placeholders [milestone, labels, assignees, reviewers]\nImproved defaults if no configuration is provided\nImproved configuration failure handling\nImprove README\nEnhanced action logs\n\n## 🐛 Fixes\n\nImproved handling for non existing tags\n\n`
|
||||||
@@ -216,7 +218,7 @@ it('Should match ordered by title DESC', async () => {
|
|||||||
|
|
||||||
it('Should ignore PRs not merged into develop branch', async () => {
|
it('Should ignore PRs not merged into develop branch', async () => {
|
||||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_base_branches_develop.json'))
|
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_base_branches_develop.json'))
|
||||||
const releaseNotes = new ReleaseNotes(octokit, {
|
const data = await pullData(octokit, {
|
||||||
owner: 'mikepenz',
|
owner: 'mikepenz',
|
||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: {name: 'v1.3.1'},
|
fromTag: {name: 'v1.3.1'},
|
||||||
@@ -228,16 +230,16 @@ it('Should ignore PRs not merged into develop branch', async () => {
|
|||||||
fetchReviews: false,
|
fetchReviews: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
})
|
}, false, false)
|
||||||
|
|
||||||
const changeLog = await releaseNotes.pull()
|
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||||
console.log(changeLog)
|
console.log(changeLog)
|
||||||
expect(changeLog).toStrictEqual(`150\n\n`)
|
expect(changeLog).toStrictEqual(`150\n\n`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should ignore PRs not merged into main branch', async () => {
|
it('Should ignore PRs not merged into main branch', async () => {
|
||||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_base_branches_main.json'))
|
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_base_branches_main.json'))
|
||||||
const releaseNotes = new ReleaseNotes(octokit, {
|
const data = await pullData(octokit, {
|
||||||
owner: 'mikepenz',
|
owner: 'mikepenz',
|
||||||
repo: 'release-changelog-builder-action',
|
repo: 'release-changelog-builder-action',
|
||||||
fromTag: {name: 'v1.3.1'},
|
fromTag: {name: 'v1.3.1'},
|
||||||
@@ -249,9 +251,9 @@ it('Should ignore PRs not merged into main branch', async () => {
|
|||||||
fetchReviews: false,
|
fetchReviews: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration
|
configuration
|
||||||
})
|
}, false, false)
|
||||||
|
|
||||||
const changeLog = await releaseNotes.pull()
|
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||||
console.log(changeLog)
|
console.log(changeLog)
|
||||||
expect(changeLog).toStrictEqual(`153\n\n`)
|
expect(changeLog).toStrictEqual(`153\n\n`)
|
||||||
})
|
})
|
||||||
+12
-12
@@ -39,7 +39,7 @@ mergedPullRequests.push(
|
|||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
repoName: 'test-repo',
|
repoName: 'test-repo',
|
||||||
labels: new Set<string>(),
|
labels: [],
|
||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body1 for this matter',
|
body: 'no magic body1 for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
@@ -57,7 +57,7 @@ mergedPullRequests.push(
|
|||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
repoName: 'test-repo',
|
repoName: 'test-repo',
|
||||||
labels: new Set<string>(),
|
labels: [],
|
||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body2 for this matter',
|
body: 'no magic body2 for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
@@ -75,7 +75,7 @@ mergedPullRequests.push(
|
|||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
repoName: 'test-repo',
|
repoName: 'test-repo',
|
||||||
labels: new Set<string>(),
|
labels: [],
|
||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body3 for this matter',
|
body: 'no magic body3 for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
@@ -93,7 +93,7 @@ mergedPullRequests.push(
|
|||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
repoName: 'test-repo',
|
repoName: 'test-repo',
|
||||||
labels: new Set<string>(),
|
labels: [],
|
||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body4 for this matter',
|
body: 'no magic body4 for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
@@ -113,7 +113,7 @@ const pullRequestWithLabelInBody: PullRequestInfo = {
|
|||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
repoName: 'test-repo',
|
repoName: 'test-repo',
|
||||||
labels: new Set<string>(),
|
labels: [],
|
||||||
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: [],
|
||||||
@@ -132,7 +132,7 @@ const openPullRequest: PullRequestInfo = {
|
|||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
repoName: 'test-repo',
|
repoName: 'test-repo',
|
||||||
labels: new Set<string>(),
|
labels: [],
|
||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'Some fancy body message',
|
body: 'Some fancy body message',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
@@ -246,7 +246,7 @@ pullRequestsWithLabels.push(
|
|||||||
mergeCommitSha: 'sha1-1',
|
mergeCommitSha: 'sha1-1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
repoName: 'test-repo',
|
repoName: 'test-repo',
|
||||||
labels: new Set<string>().add('feature'),
|
labels: ['feature'],
|
||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body for this matter',
|
body: 'no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
@@ -264,7 +264,7 @@ pullRequestsWithLabels.push(
|
|||||||
mergeCommitSha: 'sha1-2',
|
mergeCommitSha: 'sha1-2',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
repoName: 'test-repo',
|
repoName: 'test-repo',
|
||||||
labels: new Set<string>().add('issue').add('fix'),
|
labels: ['issue', 'fix'],
|
||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body for this matter',
|
body: 'no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
@@ -282,7 +282,7 @@ pullRequestsWithLabels.push(
|
|||||||
mergeCommitSha: 'sha1-3',
|
mergeCommitSha: 'sha1-3',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
repoName: 'test-repo',
|
repoName: 'test-repo',
|
||||||
labels: new Set<string>().add('issue').add('feature').add('fix'),
|
labels: ['issue', 'feature', 'fix'],
|
||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body for this matter',
|
body: 'no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
@@ -300,7 +300,7 @@ pullRequestsWithLabels.push(
|
|||||||
mergeCommitSha: 'sha1-4',
|
mergeCommitSha: 'sha1-4',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
repoName: 'test-repo',
|
repoName: 'test-repo',
|
||||||
labels: new Set<string>().add(''),
|
labels: [''],
|
||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'no magic body for this matter',
|
body: 'no magic body for this matter',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
@@ -322,7 +322,7 @@ openPullRequestsWithLabels.push(
|
|||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
repoName: 'test-repo',
|
repoName: 'test-repo',
|
||||||
labels: new Set<string>().add('feature'),
|
labels: ['feature'],
|
||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'Some fancy body message',
|
body: 'Some fancy body message',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
@@ -340,7 +340,7 @@ openPullRequestsWithLabels.push(
|
|||||||
mergeCommitSha: 'sha1',
|
mergeCommitSha: 'sha1',
|
||||||
author: 'Mike',
|
author: 'Mike',
|
||||||
repoName: 'test-repo',
|
repoName: 'test-repo',
|
||||||
labels: new Set<string>().add('feature'),
|
labels: [],
|
||||||
milestone: '',
|
milestone: '',
|
||||||
body: 'Some fancy body message',
|
body: 'Some fancy body message',
|
||||||
assignees: [],
|
assignees: [],
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ inputs:
|
|||||||
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"
|
||||||
|
exportCollected:
|
||||||
|
description: 'Enables the export of all collected PR information to an environment variable'
|
||||||
|
default: "false"
|
||||||
|
exportOnly:
|
||||||
|
description: 'If enabled, the action will only collect the data and terminate afterwards. Data can then be consumed by steps afterwards'
|
||||||
|
default: "false"
|
||||||
outputFile:
|
outputFile:
|
||||||
description: 'If defined, the changelog will get written to this file. (relative to the checkout dir)'
|
description: 'If defined, the changelog will get written to this file. (relative to the checkout dir)'
|
||||||
token:
|
token:
|
||||||
|
|||||||
+309
-245
@@ -45,6 +45,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|||||||
exports.filterCommits = exports.Commits = exports.DefaultDiffInfo = void 0;
|
exports.filterCommits = exports.Commits = exports.DefaultDiffInfo = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const moment_1 = __importDefault(__nccwpck_require__(9623));
|
const moment_1 = __importDefault(__nccwpck_require__(9623));
|
||||||
|
const utils_1 = __nccwpck_require__(918);
|
||||||
exports.DefaultDiffInfo = {
|
exports.DefaultDiffInfo = {
|
||||||
changedFiles: 0,
|
changedFiles: 0,
|
||||||
additions: 0,
|
additions: 0,
|
||||||
@@ -144,6 +145,59 @@ class Commits {
|
|||||||
});
|
});
|
||||||
return commitsResult;
|
return commitsResult;
|
||||||
}
|
}
|
||||||
|
getCommitHistory(options) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const { owner, repo, fromTag, toTag, failOnError } = options;
|
||||||
|
core.info(`ℹ️ Comparing ${owner}/${repo} - '${fromTag.name}...${toTag.name}'`);
|
||||||
|
const commitsApi = new Commits(this.octokit);
|
||||||
|
let diffInfo;
|
||||||
|
try {
|
||||||
|
diffInfo = yield commitsApi.getDiff(owner, repo, fromTag.name, toTag.name);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
(0, utils_1.failOrError)(`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, failOnError);
|
||||||
|
return exports.DefaultDiffInfo;
|
||||||
|
}
|
||||||
|
if (diffInfo.commitInfo.length === 0) {
|
||||||
|
core.warning(`⚠️ No commits found between - ${fromTag.name}...${toTag.name}`);
|
||||||
|
return exports.DefaultDiffInfo;
|
||||||
|
}
|
||||||
|
return diffInfo;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
generateCommitPRs(options) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const { owner, repo, configuration } = options;
|
||||||
|
const diffInfo = yield this.getCommitHistory(options);
|
||||||
|
const commits = diffInfo.commitInfo;
|
||||||
|
if (commits.length === 0) {
|
||||||
|
return [diffInfo, []];
|
||||||
|
}
|
||||||
|
const prCommits = filterCommits(commits, configuration.exclude_merge_branches);
|
||||||
|
core.info(`ℹ️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`);
|
||||||
|
const prs = prCommits.map(function (commit) {
|
||||||
|
return {
|
||||||
|
number: 0,
|
||||||
|
title: commit.summary,
|
||||||
|
htmlURL: '',
|
||||||
|
baseBranch: '',
|
||||||
|
createdAt: commit.date,
|
||||||
|
mergedAt: commit.date,
|
||||||
|
mergeCommitSha: commit.sha,
|
||||||
|
author: commit.author || '',
|
||||||
|
repoName: '',
|
||||||
|
labels: [],
|
||||||
|
milestone: '',
|
||||||
|
body: commit.message || '',
|
||||||
|
assignees: [],
|
||||||
|
requestedReviewers: [],
|
||||||
|
approvedReviewers: [],
|
||||||
|
status: 'merged'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return [diffInfo, prs];
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.Commits = Commits;
|
exports.Commits = Commits;
|
||||||
/**
|
/**
|
||||||
@@ -433,7 +487,9 @@ function run() {
|
|||||||
const fetchReleaseInformation = core.getInput('fetchReleaseInformation') === 'true';
|
const fetchReleaseInformation = core.getInput('fetchReleaseInformation') === 'true';
|
||||||
const fetchReviews = core.getInput('fetchReviews') === 'true';
|
const fetchReviews = core.getInput('fetchReviews') === '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, fetchReleaseInformation, fetchReviews, commitMode, configuration).build();
|
const exportCollected = core.getInput('exportCollected') === 'true';
|
||||||
|
const exportOnly = core.getInput('exportOnly') === 'true';
|
||||||
|
const result = yield new releaseNotesBuilder_1.ReleaseNotesBuilder(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen, failOnError, ignorePreReleases, fetchReviewers, fetchReleaseInformation, fetchReviews, commitMode, exportCollected, exportOnly, 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');
|
||||||
@@ -503,6 +559,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|||||||
exports.retrieveProperty = exports.compare = exports.sortPullRequests = exports.PullRequests = exports.EMPTY_COMMENT_INFO = void 0;
|
exports.retrieveProperty = exports.compare = exports.sortPullRequests = exports.PullRequests = exports.EMPTY_COMMENT_INFO = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const moment_1 = __importDefault(__nccwpck_require__(9623));
|
const moment_1 = __importDefault(__nccwpck_require__(9623));
|
||||||
|
const commits_1 = __nccwpck_require__(3916);
|
||||||
exports.EMPTY_COMMENT_INFO = {
|
exports.EMPTY_COMMENT_INFO = {
|
||||||
id: 0,
|
id: 0,
|
||||||
htmlURL: '',
|
htmlURL: '',
|
||||||
@@ -512,8 +569,9 @@ exports.EMPTY_COMMENT_INFO = {
|
|||||||
state: undefined
|
state: undefined
|
||||||
};
|
};
|
||||||
class PullRequests {
|
class PullRequests {
|
||||||
constructor(octokit) {
|
constructor(octokit, commits) {
|
||||||
this.octokit = octokit;
|
this.octokit = octokit;
|
||||||
|
this.commits = commits;
|
||||||
}
|
}
|
||||||
getSingle(owner, repo, prNumber) {
|
getSingle(owner, repo, prNumber) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@@ -662,6 +720,87 @@ class PullRequests {
|
|||||||
pr.reviews = prReviews;
|
pr.reviews = prReviews;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
getMergedPullRequests(options) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const { owner, repo, includeOpen, fetchReviewers, fetchReviews, configuration } = options;
|
||||||
|
const diffInfo = yield this.commits.getCommitHistory(options);
|
||||||
|
const commits = diffInfo.commitInfo;
|
||||||
|
if (commits.length === 0) {
|
||||||
|
return [diffInfo, []];
|
||||||
|
}
|
||||||
|
const firstCommit = commits[0];
|
||||||
|
const lastCommit = commits[commits.length - 1];
|
||||||
|
let fromDate = firstCommit.date;
|
||||||
|
const toDate = lastCommit.date;
|
||||||
|
const maxDays = configuration.max_back_track_time_days;
|
||||||
|
const maxFromDate = toDate.clone().subtract(maxDays, 'days');
|
||||||
|
if (maxFromDate.isAfter(fromDate)) {
|
||||||
|
core.info(`⚠️ Adjusted 'fromDate' to go max ${maxDays} back`);
|
||||||
|
fromDate = maxFromDate;
|
||||||
|
}
|
||||||
|
core.info(`ℹ️ Fetching PRs between dates ${fromDate.toISOString()} to ${toDate.toISOString()} for ${owner}/${repo}`);
|
||||||
|
const pullRequests = yield this.getBetweenDates(owner, repo, fromDate, toDate, configuration.max_pull_requests);
|
||||||
|
core.info(`ℹ️ Retrieved ${pullRequests.length} PRs for ${owner}/${repo} in date range from API`);
|
||||||
|
const prCommits = (0, commits_1.filterCommits)(commits, configuration.exclude_merge_branches);
|
||||||
|
core.info(`ℹ️ Retrieved ${prCommits.length} release commits for ${owner}/${repo}`);
|
||||||
|
// create array of commits for this release
|
||||||
|
const releaseCommitHashes = prCommits.map(commmit => {
|
||||||
|
return commmit.sha;
|
||||||
|
});
|
||||||
|
// filter out pull requests not associated with this release
|
||||||
|
const mergedPullRequests = pullRequests.filter(pr => {
|
||||||
|
return releaseCommitHashes.includes(pr.mergeCommitSha);
|
||||||
|
});
|
||||||
|
core.info(`ℹ️ Retrieved ${mergedPullRequests.length} merged PRs for ${owner}/${repo}`);
|
||||||
|
let allPullRequests = mergedPullRequests;
|
||||||
|
if (includeOpen) {
|
||||||
|
// retrieve all open pull requests
|
||||||
|
const openPullRequests = yield this.getOpen(owner, repo, configuration.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
|
||||||
|
const baseBranches = configuration.base_branches;
|
||||||
|
const baseBranchPatterns = baseBranches.map(baseBranch => {
|
||||||
|
return new RegExp(baseBranch.replace('\\\\', '\\'), 'gu');
|
||||||
|
});
|
||||||
|
// return only prs if the baseBranch is matching the configuration
|
||||||
|
const finalPrs = allPullRequests.filter(pr => {
|
||||||
|
if (baseBranches.length !== 0) {
|
||||||
|
return baseBranchPatterns.some(pattern => {
|
||||||
|
return pr.baseBranch.match(pattern) !== null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if (baseBranches.length !== 0) {
|
||||||
|
core.info(`ℹ️ Retrieved ${finalPrs.length} PRs for ${owner}/${repo} filtered by the 'base_branches' configuration.`);
|
||||||
|
}
|
||||||
|
// fetch reviewers only if enabled (requires an additional API request per PR)
|
||||||
|
if (fetchReviews || fetchReviewers) {
|
||||||
|
core.info(`ℹ️ Fetching reviews (or reviewers) was enabled`);
|
||||||
|
// update PR information with reviewers who approved
|
||||||
|
for (const pr of finalPrs) {
|
||||||
|
yield this.getReviews(owner, repo, pr);
|
||||||
|
const reviews = pr.reviews;
|
||||||
|
if (reviews && ((reviews === null || reviews === void 0 ? void 0 : reviews.length) || 0) > 0) {
|
||||||
|
core.info(`ℹ️ Retrieved ${reviews.length || 0} review(s) for PR ${owner}/${repo}/#${pr.number}`);
|
||||||
|
// backwards compatiblity
|
||||||
|
pr.approvedReviewers = reviews.filter(r => r.state === 'APPROVED').map(r => r.author);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.debug(`No reviewer(s) for PR ${owner}/${repo}/#${pr.number}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.debug(`ℹ️ Fetching reviews (or reviewers) was disabled`);
|
||||||
|
}
|
||||||
|
return [diffInfo, finalPrs];
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.PullRequests = PullRequests;
|
exports.PullRequests = PullRequests;
|
||||||
function sortPrs(pullRequests) {
|
function sortPrs(pullRequests) {
|
||||||
@@ -736,7 +875,7 @@ function retrieveProperty(pr, property, useCase) {
|
|||||||
exports.retrieveProperty = retrieveProperty;
|
exports.retrieveProperty = retrieveProperty;
|
||||||
// helper function to add a special open label to prs not merged.
|
// helper function to add a special open label to prs not merged.
|
||||||
function attachSpeciaLabels(status, labels) {
|
function attachSpeciaLabels(status, labels) {
|
||||||
labels.add(`--rcba-${status}`);
|
labels.push(`--rcba-${status}`);
|
||||||
return labels;
|
return labels;
|
||||||
}
|
}
|
||||||
const mapPullRequest = (pr, status = 'open') => {
|
const mapPullRequest = (pr, status = 'open') => {
|
||||||
@@ -752,7 +891,7 @@ const mapPullRequest = (pr, status = 'open') => {
|
|||||||
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: 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')) || ''; })) || [])),
|
labels: attachSpeciaLabels(status, ((_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) || '')) || [],
|
||||||
@@ -900,236 +1039,6 @@ function buildRegex(regex, target, onProperty, method, onEmpty) {
|
|||||||
exports.buildRegex = buildRegex;
|
exports.buildRegex = buildRegex;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
|
||||||
|
|
||||||
/***/ 5882:
|
|
||||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
||||||
exports.ReleaseNotes = void 0;
|
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
|
||||||
const commits_1 = __nccwpck_require__(3916);
|
|
||||||
const pullRequests_1 = __nccwpck_require__(4217);
|
|
||||||
const transform_1 = __nccwpck_require__(1644);
|
|
||||||
const utils_1 = __nccwpck_require__(918);
|
|
||||||
class ReleaseNotes {
|
|
||||||
constructor(octokit, options) {
|
|
||||||
this.octokit = octokit;
|
|
||||||
this.options = options;
|
|
||||||
}
|
|
||||||
pull() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
let mergedPullRequests;
|
|
||||||
let diffInfo;
|
|
||||||
if (!this.options.commitMode) {
|
|
||||||
core.startGroup(`🚀 Load pull requests`);
|
|
||||||
const [info, prs] = yield this.getMergedPullRequests(this.octokit);
|
|
||||||
mergedPullRequests = prs;
|
|
||||||
diffInfo = info;
|
|
||||||
// define the included PRs within this release as output
|
|
||||||
core.setOutput('pull_requests', mergedPullRequests
|
|
||||||
.map(pr => {
|
|
||||||
return pr.number;
|
|
||||||
})
|
|
||||||
.join(','));
|
|
||||||
core.endGroup();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
core.startGroup(`🚀 Load commit history`);
|
|
||||||
core.info(`⚠️ Executing experimental commit mode`);
|
|
||||||
const [info, prs] = yield this.generateCommitPRs(this.octokit);
|
|
||||||
mergedPullRequests = prs;
|
|
||||||
diffInfo = info;
|
|
||||||
core.endGroup();
|
|
||||||
}
|
|
||||||
core.setOutput('changed_files', diffInfo.changedFiles);
|
|
||||||
core.setOutput('additions', diffInfo.additions);
|
|
||||||
core.setOutput('deletions', diffInfo.deletions);
|
|
||||||
core.setOutput('changes', diffInfo.changes);
|
|
||||||
core.setOutput('commits', diffInfo.commits);
|
|
||||||
if (mergedPullRequests.length === 0) {
|
|
||||||
core.warning(`⚠️ No pull requests found`);
|
|
||||||
return (0, transform_1.replaceEmptyTemplate)(this.options.configuration.empty_template, this.options);
|
|
||||||
}
|
|
||||||
core.startGroup('📦 Build changelog');
|
|
||||||
const resultChangelog = (0, transform_1.buildChangelog)(diffInfo, mergedPullRequests, this.options);
|
|
||||||
core.endGroup();
|
|
||||||
return resultChangelog;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getCommitHistory(octokit) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const { owner, repo, fromTag, toTag, failOnError } = this.options;
|
|
||||||
core.info(`ℹ️ Comparing ${owner}/${repo} - '${fromTag.name}...${toTag.name}'`);
|
|
||||||
const commitsApi = new commits_1.Commits(octokit);
|
|
||||||
let diffInfo;
|
|
||||||
try {
|
|
||||||
diffInfo = yield commitsApi.getDiff(owner, repo, fromTag.name, toTag.name);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
(0, utils_1.failOrError)(`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, failOnError);
|
|
||||||
return commits_1.DefaultDiffInfo;
|
|
||||||
}
|
|
||||||
if (diffInfo.commitInfo.length === 0) {
|
|
||||||
core.warning(`⚠️ No commits found between - ${fromTag.name}...${toTag.name}`);
|
|
||||||
return commits_1.DefaultDiffInfo;
|
|
||||||
}
|
|
||||||
return diffInfo;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getMergedPullRequests(octokit) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const { owner, repo, includeOpen, fetchReviewers, fetchReviews, configuration } = this.options;
|
|
||||||
const diffInfo = yield this.getCommitHistory(octokit);
|
|
||||||
const commits = diffInfo.commitInfo;
|
|
||||||
if (commits.length === 0) {
|
|
||||||
return [diffInfo, []];
|
|
||||||
}
|
|
||||||
const firstCommit = commits[0];
|
|
||||||
const lastCommit = commits[commits.length - 1];
|
|
||||||
let fromDate = firstCommit.date;
|
|
||||||
const toDate = lastCommit.date;
|
|
||||||
const maxDays = configuration.max_back_track_time_days;
|
|
||||||
const maxFromDate = toDate.clone().subtract(maxDays, 'days');
|
|
||||||
if (maxFromDate.isAfter(fromDate)) {
|
|
||||||
core.info(`⚠️ Adjusted 'fromDate' to go max ${maxDays} back`);
|
|
||||||
fromDate = maxFromDate;
|
|
||||||
}
|
|
||||||
core.info(`ℹ️ Fetching PRs between dates ${fromDate.toISOString()} to ${toDate.toISOString()} for ${owner}/${repo}`);
|
|
||||||
const pullRequestsApi = new pullRequests_1.PullRequests(octokit);
|
|
||||||
const pullRequests = yield pullRequestsApi.getBetweenDates(owner, repo, fromDate, toDate, configuration.max_pull_requests);
|
|
||||||
core.info(`ℹ️ Retrieved ${pullRequests.length} PRs for ${owner}/${repo} in date range from API`);
|
|
||||||
const prCommits = (0, commits_1.filterCommits)(commits, configuration.exclude_merge_branches);
|
|
||||||
core.info(`ℹ️ Retrieved ${prCommits.length} release commits for ${owner}/${repo}`);
|
|
||||||
// create array of commits for this release
|
|
||||||
const releaseCommitHashes = prCommits.map(commmit => {
|
|
||||||
return commmit.sha;
|
|
||||||
});
|
|
||||||
// filter out pull requests not associated with this release
|
|
||||||
const mergedPullRequests = pullRequests.filter(pr => {
|
|
||||||
return releaseCommitHashes.includes(pr.mergeCommitSha);
|
|
||||||
});
|
|
||||||
core.info(`ℹ️ Retrieved ${mergedPullRequests.length} merged PRs for ${owner}/${repo}`);
|
|
||||||
let allPullRequests = mergedPullRequests;
|
|
||||||
if (includeOpen) {
|
|
||||||
// retrieve all open pull requests
|
|
||||||
const openPullRequests = yield pullRequestsApi.getOpen(owner, repo, configuration.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
|
|
||||||
const baseBranches = configuration.base_branches;
|
|
||||||
const baseBranchPatterns = baseBranches.map(baseBranch => {
|
|
||||||
return new RegExp(baseBranch.replace('\\\\', '\\'), 'gu');
|
|
||||||
});
|
|
||||||
// return only prs if the baseBranch is matching the configuration
|
|
||||||
const finalPrs = allPullRequests.filter(pr => {
|
|
||||||
if (baseBranches.length !== 0) {
|
|
||||||
return baseBranchPatterns.some(pattern => {
|
|
||||||
return pr.baseBranch.match(pattern) !== null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
if (baseBranches.length !== 0) {
|
|
||||||
core.info(`ℹ️ Retrieved ${finalPrs.length} PRs for ${owner}/${repo} filtered by the 'base_branches' configuration.`);
|
|
||||||
}
|
|
||||||
// fetch reviewers only if enabled (requires an additional API request per PR)
|
|
||||||
if (fetchReviews || fetchReviewers) {
|
|
||||||
core.info(`ℹ️ Fetching reviews (or reviewers) was enabled`);
|
|
||||||
// update PR information with reviewers who approved
|
|
||||||
for (const pr of finalPrs) {
|
|
||||||
yield pullRequestsApi.getReviews(owner, repo, pr);
|
|
||||||
const reviews = pr.reviews;
|
|
||||||
if (reviews && ((reviews === null || reviews === void 0 ? void 0 : reviews.length) || 0) > 0) {
|
|
||||||
core.info(`ℹ️ Retrieved ${reviews.length || 0} review(s) for PR ${owner}/${repo}/#${pr.number}`);
|
|
||||||
// backwards compatiblity
|
|
||||||
pr.approvedReviewers = reviews.filter(r => r.state === 'APPROVED').map(r => r.author);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
core.debug(`No reviewer(s) for PR ${owner}/${repo}/#${pr.number}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
core.debug(`ℹ️ Fetching reviews (or reviewers) was disabled`);
|
|
||||||
}
|
|
||||||
return [diffInfo, finalPrs];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
generateCommitPRs(octokit) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const { owner, repo, configuration } = this.options;
|
|
||||||
const diffInfo = yield this.getCommitHistory(octokit);
|
|
||||||
const commits = diffInfo.commitInfo;
|
|
||||||
if (commits.length === 0) {
|
|
||||||
return [diffInfo, []];
|
|
||||||
}
|
|
||||||
const prCommits = (0, commits_1.filterCommits)(commits, configuration.exclude_merge_branches);
|
|
||||||
core.info(`ℹ️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`);
|
|
||||||
const prs = prCommits.map(function (commit) {
|
|
||||||
return {
|
|
||||||
number: 0,
|
|
||||||
title: commit.summary,
|
|
||||||
htmlURL: '',
|
|
||||||
baseBranch: '',
|
|
||||||
createdAt: commit.date,
|
|
||||||
mergedAt: commit.date,
|
|
||||||
mergeCommitSha: commit.sha,
|
|
||||||
author: commit.author || '',
|
|
||||||
repoName: '',
|
|
||||||
labels: new Set(),
|
|
||||||
milestone: '',
|
|
||||||
body: commit.message || '',
|
|
||||||
assignees: [],
|
|
||||||
requestedReviewers: [],
|
|
||||||
approvedReviewers: [],
|
|
||||||
status: 'merged'
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return [diffInfo, prs];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.ReleaseNotes = ReleaseNotes;
|
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 4883:
|
/***/ 4883:
|
||||||
@@ -1170,15 +1079,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.ReleaseNotesBuilder = void 0;
|
exports.pullData = exports.ReleaseNotesBuilder = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const rest_1 = __nccwpck_require__(5375);
|
const rest_1 = __nccwpck_require__(5375);
|
||||||
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);
|
||||||
const https_proxy_agent_1 = __nccwpck_require__(7219);
|
const https_proxy_agent_1 = __nccwpck_require__(7219);
|
||||||
|
const pullRequests_1 = __nccwpck_require__(4217);
|
||||||
|
const commits_1 = __nccwpck_require__(3916);
|
||||||
|
const transform_1 = __nccwpck_require__(1644);
|
||||||
class ReleaseNotesBuilder {
|
class ReleaseNotesBuilder {
|
||||||
constructor(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen = false, failOnError, ignorePreReleases, fetchReviewers = false, fetchReleaseInformation = false, fetchReviews = false, commitMode, configuration) {
|
constructor(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen = false, failOnError, ignorePreReleases, fetchReviewers = false, fetchReleaseInformation = false, fetchReviews = false, commitMode = false, exportCollected = false, exportOnly = false, configuration) {
|
||||||
this.baseUrl = baseUrl;
|
this.baseUrl = baseUrl;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.repositoryPath = repositoryPath;
|
this.repositoryPath = repositoryPath;
|
||||||
@@ -1193,10 +1104,14 @@ class ReleaseNotesBuilder {
|
|||||||
this.fetchReleaseInformation = fetchReleaseInformation;
|
this.fetchReleaseInformation = fetchReleaseInformation;
|
||||||
this.fetchReviews = fetchReviews;
|
this.fetchReviews = fetchReviews;
|
||||||
this.commitMode = commitMode;
|
this.commitMode = commitMode;
|
||||||
|
this.exportCollected = exportCollected;
|
||||||
|
this.exportOnly = exportOnly;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
}
|
}
|
||||||
build() {
|
build() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
let releaseNotesData = (0, utils_1.checkExportedData)();
|
||||||
|
if (releaseNotesData == null) {
|
||||||
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);
|
||||||
return null;
|
return null;
|
||||||
@@ -1278,12 +1193,105 @@ class ReleaseNotesBuilder {
|
|||||||
commitMode: this.commitMode,
|
commitMode: this.commitMode,
|
||||||
configuration: this.configuration
|
configuration: this.configuration
|
||||||
};
|
};
|
||||||
const releaseNotes = new releaseNotes_1.ReleaseNotes(octokit, options);
|
releaseNotesData = yield pullData(octokit, options, this.exportCollected, this.exportOnly);
|
||||||
return yield releaseNotes.pull();
|
}
|
||||||
|
else {
|
||||||
|
core.info(`ℹ️ Retrieved previously exported collected data`);
|
||||||
|
// merge input with options (in case some data was updated)
|
||||||
|
const diffInfo = releaseNotesData.diffInfo;
|
||||||
|
const mergedPullRequests = releaseNotesData.mergedPullRequests;
|
||||||
|
const orgOptions = releaseNotesData.options;
|
||||||
|
// merge fromTag info with provided info || otherwise use cached info
|
||||||
|
const fromTag = orgOptions.fromTag;
|
||||||
|
if (this.fromTag != null) {
|
||||||
|
fromTag.name = this.fromTag;
|
||||||
|
}
|
||||||
|
const toTag = orgOptions.toTag;
|
||||||
|
if (this.toTag != null) {
|
||||||
|
toTag.name = this.toTag;
|
||||||
|
}
|
||||||
|
// merge provided values with previous options (prefer provided)
|
||||||
|
const options = {
|
||||||
|
owner: this.owner || orgOptions.owner,
|
||||||
|
repo: this.repo || orgOptions.repo,
|
||||||
|
fromTag,
|
||||||
|
toTag,
|
||||||
|
includeOpen: this.includeOpen || orgOptions.includeOpen,
|
||||||
|
failOnError: this.failOnError || orgOptions.failOnError,
|
||||||
|
fetchReviewers: this.fetchReviewers || orgOptions.fetchReviewers,
|
||||||
|
fetchReleaseInformation: this.fetchReleaseInformation || orgOptions.fetchReleaseInformation,
|
||||||
|
fetchReviews: this.fetchReviews || orgOptions.fetchReviews,
|
||||||
|
commitMode: this.commitMode || orgOptions.commitMode,
|
||||||
|
configuration: this.configuration || orgOptions.configuration
|
||||||
|
};
|
||||||
|
releaseNotesData = {
|
||||||
|
diffInfo,
|
||||||
|
mergedPullRequests,
|
||||||
|
options
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (releaseNotesData != null) {
|
||||||
|
return (0, transform_1.buildChangelog)(releaseNotesData.diffInfo, releaseNotesData.mergedPullRequests, releaseNotesData.options);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.ReleaseNotesBuilder = ReleaseNotesBuilder;
|
exports.ReleaseNotesBuilder = ReleaseNotesBuilder;
|
||||||
|
function pullData(octokit, options, exportCollected, exportOnly) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
let mergedPullRequests;
|
||||||
|
let diffInfo;
|
||||||
|
const commitsApi = new commits_1.Commits(octokit);
|
||||||
|
if (!options.commitMode) {
|
||||||
|
core.startGroup(`🚀 Load pull requests`);
|
||||||
|
const pullRequestsApi = new pullRequests_1.PullRequests(octokit, commitsApi);
|
||||||
|
const [info, prs] = yield pullRequestsApi.getMergedPullRequests(options);
|
||||||
|
mergedPullRequests = prs;
|
||||||
|
diffInfo = info;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.startGroup(`🚀 Load commit history`);
|
||||||
|
core.info(`⚠️ Executing experimental commit mode`);
|
||||||
|
const [info, prs] = yield commitsApi.generateCommitPRs(options);
|
||||||
|
mergedPullRequests = prs;
|
||||||
|
diffInfo = info;
|
||||||
|
}
|
||||||
|
// define the included PRs within this release as output
|
||||||
|
core.setOutput('pull_requests', mergedPullRequests
|
||||||
|
.map(pr => {
|
||||||
|
return pr.number;
|
||||||
|
})
|
||||||
|
.join(','));
|
||||||
|
core.setOutput('changed_files', diffInfo.changedFiles);
|
||||||
|
core.setOutput('additions', diffInfo.additions);
|
||||||
|
core.setOutput('deletions', diffInfo.deletions);
|
||||||
|
core.setOutput('changes', diffInfo.changes);
|
||||||
|
core.setOutput('commits', diffInfo.commits);
|
||||||
|
if (exportCollected) {
|
||||||
|
core.info('📦 Exporting collected data');
|
||||||
|
core.exportVariable(`RCBA_EXPORT_diffInfo`, JSON.stringify(diffInfo));
|
||||||
|
//fs.writeFileSync(path.resolve('diffInfo.json'), JSON.stringify(diffInfo))
|
||||||
|
core.exportVariable(`RCBA_EXPORT_mergedPullRequests`, JSON.stringify(mergedPullRequests));
|
||||||
|
//fs.writeFileSync(path.resolve('mergedPullRequests.json'), JSON.stringify(mergedPullRequests))
|
||||||
|
core.exportVariable(`RCBA_EXPORT_options`, JSON.stringify(options));
|
||||||
|
//fs.writeFileSync(path.resolve('options.json'), JSON.stringify(options))
|
||||||
|
if (exportOnly) {
|
||||||
|
core.endGroup();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core.endGroup();
|
||||||
|
return {
|
||||||
|
diffInfo,
|
||||||
|
mergedPullRequests,
|
||||||
|
options
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.pullData = pullData;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
@@ -1687,6 +1695,13 @@ const utils_1 = __nccwpck_require__(918);
|
|||||||
const regexUtils_1 = __nccwpck_require__(2364);
|
const regexUtils_1 = __nccwpck_require__(2364);
|
||||||
const EMPTY_MAP = new Map();
|
const EMPTY_MAP = new Map();
|
||||||
function buildChangelog(diffInfo, prs, options) {
|
function buildChangelog(diffInfo, prs, options) {
|
||||||
|
core.startGroup('📦 Build changelog');
|
||||||
|
if (prs.length === 0) {
|
||||||
|
core.warning(`⚠️ No pull requests found`);
|
||||||
|
const result = replaceEmptyTemplate(options.configuration.empty_template, options);
|
||||||
|
core.endGroup();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
// sort to target order
|
// sort to target order
|
||||||
const config = options.configuration;
|
const config = options.configuration;
|
||||||
const sort = config.sort;
|
const sort = config.sort;
|
||||||
@@ -1726,7 +1741,7 @@ function buildChangelog(diffInfo, prs, options) {
|
|||||||
const extracted = extractValues(pr, extractor, 'label_extractor');
|
const extracted = extractValues(pr, extractor, 'label_extractor');
|
||||||
if (extracted !== null) {
|
if (extracted !== null) {
|
||||||
for (const label of extracted) {
|
for (const label of extracted) {
|
||||||
pr.labels.add(label);
|
pr.labels.push(label);
|
||||||
}
|
}
|
||||||
if (core.isDebug()) {
|
if (core.isDebug()) {
|
||||||
core.debug(` Extracted the following labels (${JSON.stringify(extracted)}) for PR ${pr.number}`);
|
core.debug(` Extracted the following labels (${JSON.stringify(extracted)}) for PR ${pr.number}`);
|
||||||
@@ -1761,7 +1776,7 @@ function buildChangelog(diffInfo, prs, options) {
|
|||||||
const uncategorizedPrs = [];
|
const uncategorizedPrs = [];
|
||||||
// bring elements in order
|
// bring elements in order
|
||||||
for (const [pr, body] of transformedMap) {
|
for (const [pr, body] of transformedMap) {
|
||||||
if ((0, utils_1.haveCommonElements)(ignoredLabels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
|
if ((0, utils_1.haveCommonElementsArr)(ignoredLabels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
|
||||||
ignoredPrs.push(body);
|
ignoredPrs.push(body);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1773,7 +1788,7 @@ function buildChangelog(diffInfo, prs, options) {
|
|||||||
let matched = false; // check if we matched within the given category
|
let matched = false; // check if we matched within the given category
|
||||||
// check if any exclude label matches
|
// check if any exclude label matches
|
||||||
if (category.exclude_labels !== undefined) {
|
if (category.exclude_labels !== undefined) {
|
||||||
if ((0, utils_1.haveCommonElements)(category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
|
if ((0, utils_1.haveCommonElementsArr)(category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
|
||||||
if (core.isDebug()) {
|
if (core.isDebug()) {
|
||||||
const excludeLabels = JSON.stringify(category.exclude_labels);
|
const excludeLabels = JSON.stringify(category.exclude_labels);
|
||||||
core.debug(` PR ${pr.number} with labels: ${pr.labels} excluded from category via exclude label: ${excludeLabels}`);
|
core.debug(` PR ${pr.number} with labels: ${pr.labels} excluded from category via exclude label: ${excludeLabels}`);
|
||||||
@@ -1785,7 +1800,7 @@ function buildChangelog(diffInfo, prs, options) {
|
|||||||
// validate for an exhaustive match (e.g. every provided rule applies)
|
// validate for an exhaustive match (e.g. every provided rule applies)
|
||||||
if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) {
|
if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) {
|
||||||
if (category.labels !== undefined) {
|
if (category.labels !== undefined) {
|
||||||
matched = (0, utils_1.haveEveryElements)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels);
|
matched = (0, utils_1.haveEveryElementsArr)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels);
|
||||||
}
|
}
|
||||||
let exhaustive_rules = true;
|
let exhaustive_rules = true;
|
||||||
if (category.exhaustive_rules !== undefined) {
|
if (category.exhaustive_rules !== undefined) {
|
||||||
@@ -1799,7 +1814,7 @@ function buildChangelog(diffInfo, prs, options) {
|
|||||||
// if not exhaustive, do individual matches
|
// if not exhaustive, do individual matches
|
||||||
if (category.labels !== undefined) {
|
if (category.labels !== undefined) {
|
||||||
// check if either any of the labels applies
|
// check if either any of the labels applies
|
||||||
matched = (0, utils_1.haveCommonElements)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels);
|
matched = (0, utils_1.haveCommonElementsArr)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels);
|
||||||
}
|
}
|
||||||
let exhaustive_rules = false;
|
let exhaustive_rules = false;
|
||||||
if (category.exhaustive_rules !== undefined) {
|
if (category.exhaustive_rules !== undefined) {
|
||||||
@@ -1916,6 +1931,7 @@ function buildChangelog(diffInfo, prs, options) {
|
|||||||
transformedChangelog = replacePrPlaceholders(transformedChangelog, placeholderPrMap, config);
|
transformedChangelog = replacePrPlaceholders(transformedChangelog, placeholderPrMap, config);
|
||||||
transformedChangelog = cleanupPrPlaceholders(transformedChangelog, placeholders);
|
transformedChangelog = cleanupPrPlaceholders(transformedChangelog, placeholders);
|
||||||
core.info(`ℹ️ Filled template`);
|
core.info(`ℹ️ Filled template`);
|
||||||
|
core.endGroup();
|
||||||
return transformedChangelog;
|
return transformedChangelog;
|
||||||
}
|
}
|
||||||
exports.buildChangelog = buildChangelog;
|
exports.buildChangelog = buildChangelog;
|
||||||
@@ -2145,12 +2161,16 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
__setModuleDefault(result, mod);
|
__setModuleDefault(result, mod);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
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.haveEveryElements = exports.haveCommonElements = exports.createOrSet = exports.writeOutput = exports.directoryExistsSync = exports.mergeConfiguration = exports.parseConfiguration = exports.resolveConfiguration = exports.failOrError = exports.retrieveRepositoryPath = void 0;
|
exports.haveEveryElementsArr = exports.haveEveryElements = exports.haveCommonElementsArr = exports.haveCommonElements = exports.createOrSet = exports.writeOutput = exports.directoryExistsSync = exports.mergeConfiguration = exports.parseConfiguration = exports.resolveConfiguration = exports.checkExportedData = exports.failOrError = exports.retrieveRepositoryPath = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const fs = __importStar(__nccwpck_require__(7147));
|
const fs = __importStar(__nccwpck_require__(7147));
|
||||||
const path = __importStar(__nccwpck_require__(1017));
|
const path = __importStar(__nccwpck_require__(1017));
|
||||||
const configuration_1 = __nccwpck_require__(5527);
|
const configuration_1 = __nccwpck_require__(5527);
|
||||||
|
const moment_1 = __importDefault(__nccwpck_require__(9623));
|
||||||
/**
|
/**
|
||||||
* Resolves the repository path, relatively to the GITHUB_WORKSPACE
|
* Resolves the repository path, relatively to the GITHUB_WORKSPACE
|
||||||
*/
|
*/
|
||||||
@@ -2181,6 +2201,42 @@ function failOrError(message, failOnError) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.failOrError = failOrError;
|
exports.failOrError = failOrError;
|
||||||
|
/**
|
||||||
|
* Retrieves the exported information from a previous run of the `release-changelog-builder-action`.
|
||||||
|
* If available, return a [ReleaseNotesData].
|
||||||
|
*/
|
||||||
|
function checkExportedData() {
|
||||||
|
const rawDiffInfo = process.env[`RCBA_EXPORT_diffInfo`];
|
||||||
|
const rawMergedPullRequests = process.env[`RCBA_EXPORT_mergedPullRequests`];
|
||||||
|
const rawOptions = process.env[`RCBA_EXPORT_options`];
|
||||||
|
if (rawDiffInfo && rawMergedPullRequests && rawOptions) {
|
||||||
|
const diffInfo = JSON.parse(rawDiffInfo);
|
||||||
|
const mergedPullRequests = JSON.parse(rawMergedPullRequests);
|
||||||
|
for (const pr of mergedPullRequests) {
|
||||||
|
pr.createdAt = (0, moment_1.default)(pr.createdAt);
|
||||||
|
if (pr.mergedAt) {
|
||||||
|
pr.mergedAt = (0, moment_1.default)(pr.mergedAt);
|
||||||
|
}
|
||||||
|
if (pr.reviews) {
|
||||||
|
for (const review of pr.reviews) {
|
||||||
|
if (review.submittedAt) {
|
||||||
|
review.submittedAt = (0, moment_1.default)(review.submittedAt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const options = JSON.parse(rawOptions);
|
||||||
|
return {
|
||||||
|
diffInfo,
|
||||||
|
mergedPullRequests,
|
||||||
|
options
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.checkExportedData = checkExportedData;
|
||||||
/**
|
/**
|
||||||
* Retrieves the configuration given the file path, if not found it will fallback to the `DefaultConfiguration`
|
* Retrieves the configuration given the file path, if not found it will fallback to the `DefaultConfiguration`
|
||||||
*/
|
*/
|
||||||
@@ -2322,10 +2378,18 @@ function haveCommonElements(arr1, arr2) {
|
|||||||
return arr1.some(item => arr2.has(item));
|
return arr1.some(item => arr2.has(item));
|
||||||
}
|
}
|
||||||
exports.haveCommonElements = haveCommonElements;
|
exports.haveCommonElements = haveCommonElements;
|
||||||
|
function haveCommonElementsArr(arr1, arr2) {
|
||||||
|
return haveCommonElements(arr1, new Set(arr2));
|
||||||
|
}
|
||||||
|
exports.haveCommonElementsArr = haveCommonElementsArr;
|
||||||
function haveEveryElements(arr1, arr2) {
|
function haveEveryElements(arr1, arr2) {
|
||||||
return arr1.every(item => arr2.has(item));
|
return arr1.every(item => arr2.has(item));
|
||||||
}
|
}
|
||||||
exports.haveEveryElements = haveEveryElements;
|
exports.haveEveryElements = haveEveryElements;
|
||||||
|
function haveEveryElementsArr(arr1, arr2) {
|
||||||
|
return haveEveryElements(arr1, new Set(arr2));
|
||||||
|
}
|
||||||
|
exports.haveEveryElementsArr = haveEveryElementsArr;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,6 +1,9 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
|
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
import {failOrError} from './utils'
|
||||||
|
import {ReleaseNotesOptions} from './releaseNotesBuilder'
|
||||||
|
import {PullRequestInfo} from './pullRequests'
|
||||||
|
|
||||||
export interface DiffInfo {
|
export interface DiffInfo {
|
||||||
changedFiles: number
|
changedFiles: number
|
||||||
@@ -117,6 +120,62 @@ export class Commits {
|
|||||||
|
|
||||||
return commitsResult
|
return commitsResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getCommitHistory(options: ReleaseNotesOptions): Promise<DiffInfo> {
|
||||||
|
const {owner, repo, fromTag, toTag, failOnError} = options
|
||||||
|
core.info(`ℹ️ Comparing ${owner}/${repo} - '${fromTag.name}...${toTag.name}'`)
|
||||||
|
|
||||||
|
const commitsApi = new Commits(this.octokit)
|
||||||
|
let diffInfo: DiffInfo
|
||||||
|
try {
|
||||||
|
diffInfo = await commitsApi.getDiff(owner, repo, fromTag.name, toTag.name)
|
||||||
|
} catch (error) {
|
||||||
|
failOrError(`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, failOnError)
|
||||||
|
return DefaultDiffInfo
|
||||||
|
}
|
||||||
|
if (diffInfo.commitInfo.length === 0) {
|
||||||
|
core.warning(`⚠️ No commits found between - ${fromTag.name}...${toTag.name}`)
|
||||||
|
return DefaultDiffInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
return diffInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateCommitPRs(options: ReleaseNotesOptions): Promise<[DiffInfo, PullRequestInfo[]]> {
|
||||||
|
const {owner, repo, configuration} = options
|
||||||
|
|
||||||
|
const diffInfo = await this.getCommitHistory(options)
|
||||||
|
const commits = diffInfo.commitInfo
|
||||||
|
if (commits.length === 0) {
|
||||||
|
return [diffInfo, []]
|
||||||
|
}
|
||||||
|
|
||||||
|
const prCommits = filterCommits(commits, configuration.exclude_merge_branches)
|
||||||
|
|
||||||
|
core.info(`ℹ️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`)
|
||||||
|
|
||||||
|
const prs = prCommits.map(function (commit): PullRequestInfo {
|
||||||
|
return {
|
||||||
|
number: 0,
|
||||||
|
title: commit.summary,
|
||||||
|
htmlURL: '',
|
||||||
|
baseBranch: '',
|
||||||
|
createdAt: commit.date,
|
||||||
|
mergedAt: commit.date,
|
||||||
|
mergeCommitSha: commit.sha,
|
||||||
|
author: commit.author || '',
|
||||||
|
repoName: '',
|
||||||
|
labels: [],
|
||||||
|
milestone: '',
|
||||||
|
body: commit.message || '',
|
||||||
|
assignees: [],
|
||||||
|
requestedReviewers: [],
|
||||||
|
approvedReviewers: [],
|
||||||
|
status: 'merged'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return [diffInfo, prs]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ async function run(): Promise<void> {
|
|||||||
const fetchReleaseInformation = core.getInput('fetchReleaseInformation') === 'true'
|
const fetchReleaseInformation = core.getInput('fetchReleaseInformation') === 'true'
|
||||||
const fetchReviews = core.getInput('fetchReviews') === 'true'
|
const fetchReviews = core.getInput('fetchReviews') === 'true'
|
||||||
const commitMode = core.getInput('commitMode') === 'true'
|
const commitMode = core.getInput('commitMode') === 'true'
|
||||||
|
const exportCollected = core.getInput('exportCollected') === 'true'
|
||||||
|
const exportOnly = core.getInput('exportOnly') === 'true'
|
||||||
|
|
||||||
const result = await new ReleaseNotesBuilder(
|
const result = await new ReleaseNotesBuilder(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
@@ -70,6 +72,8 @@ async function run(): Promise<void> {
|
|||||||
fetchReleaseInformation,
|
fetchReleaseInformation,
|
||||||
fetchReviews,
|
fetchReviews,
|
||||||
commitMode,
|
commitMode,
|
||||||
|
exportCollected,
|
||||||
|
exportOnly,
|
||||||
configuration
|
configuration
|
||||||
).build()
|
).build()
|
||||||
|
|
||||||
|
|||||||
+107
-5
@@ -3,6 +3,8 @@ import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
|
|||||||
import {Unpacked} from './utils'
|
import {Unpacked} from './utils'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import {Property, Sort} from './configuration'
|
import {Property, Sort} from './configuration'
|
||||||
|
import {Commits, DiffInfo, filterCommits} from './commits'
|
||||||
|
import {ReleaseNotesOptions} from './releaseNotesBuilder'
|
||||||
|
|
||||||
export interface PullRequestInfo {
|
export interface PullRequestInfo {
|
||||||
number: number
|
number: number
|
||||||
@@ -15,7 +17,7 @@ export interface PullRequestInfo {
|
|||||||
mergeCommitSha: string
|
mergeCommitSha: string
|
||||||
author: string
|
author: string
|
||||||
repoName: string
|
repoName: string
|
||||||
labels: Set<string>
|
labels: string[]
|
||||||
milestone: string
|
milestone: string
|
||||||
body: string
|
body: string
|
||||||
assignees: string[]
|
assignees: string[]
|
||||||
@@ -50,7 +52,7 @@ type PullsListData = RestEndpointMethodTypes['pulls']['list']['response']['data'
|
|||||||
type PullReviewsData = RestEndpointMethodTypes['pulls']['listReviews']['response']['data']
|
type PullReviewsData = RestEndpointMethodTypes['pulls']['listReviews']['response']['data']
|
||||||
|
|
||||||
export class PullRequests {
|
export class PullRequests {
|
||||||
constructor(private octokit: Octokit) {}
|
constructor(private octokit: Octokit, private commits: Commits) {}
|
||||||
|
|
||||||
async getSingle(owner: string, repo: string, prNumber: number): Promise<PullRequestInfo | null> {
|
async getSingle(owner: string, repo: string, prNumber: number): Promise<PullRequestInfo | null> {
|
||||||
try {
|
try {
|
||||||
@@ -159,6 +161,106 @@ export class PullRequests {
|
|||||||
}
|
}
|
||||||
pr.reviews = prReviews
|
pr.reviews = prReviews
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getMergedPullRequests(options: ReleaseNotesOptions): Promise<[DiffInfo, PullRequestInfo[]]> {
|
||||||
|
const {owner, repo, includeOpen, fetchReviewers, fetchReviews, configuration} = options
|
||||||
|
|
||||||
|
const diffInfo = await this.commits.getCommitHistory(options)
|
||||||
|
const commits = diffInfo.commitInfo
|
||||||
|
if (commits.length === 0) {
|
||||||
|
return [diffInfo, []]
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstCommit = commits[0]
|
||||||
|
const lastCommit = commits[commits.length - 1]
|
||||||
|
let fromDate = firstCommit.date
|
||||||
|
const toDate = lastCommit.date
|
||||||
|
|
||||||
|
const maxDays = configuration.max_back_track_time_days
|
||||||
|
const maxFromDate = toDate.clone().subtract(maxDays, 'days')
|
||||||
|
if (maxFromDate.isAfter(fromDate)) {
|
||||||
|
core.info(`⚠️ Adjusted 'fromDate' to go max ${maxDays} back`)
|
||||||
|
fromDate = maxFromDate
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info(`ℹ️ Fetching PRs between dates ${fromDate.toISOString()} to ${toDate.toISOString()} for ${owner}/${repo}`)
|
||||||
|
|
||||||
|
const pullRequests = await this.getBetweenDates(owner, repo, fromDate, toDate, configuration.max_pull_requests)
|
||||||
|
|
||||||
|
core.info(`ℹ️ Retrieved ${pullRequests.length} PRs for ${owner}/${repo} in date range from API`)
|
||||||
|
|
||||||
|
const prCommits = filterCommits(commits, configuration.exclude_merge_branches)
|
||||||
|
|
||||||
|
core.info(`ℹ️ Retrieved ${prCommits.length} release commits for ${owner}/${repo}`)
|
||||||
|
|
||||||
|
// create array of commits for this release
|
||||||
|
const releaseCommitHashes = prCommits.map(commmit => {
|
||||||
|
return commmit.sha
|
||||||
|
})
|
||||||
|
|
||||||
|
// filter out pull requests not associated with this release
|
||||||
|
const mergedPullRequests = pullRequests.filter(pr => {
|
||||||
|
return releaseCommitHashes.includes(pr.mergeCommitSha)
|
||||||
|
})
|
||||||
|
|
||||||
|
core.info(`ℹ️ Retrieved ${mergedPullRequests.length} merged PRs for ${owner}/${repo}`)
|
||||||
|
|
||||||
|
let allPullRequests = mergedPullRequests
|
||||||
|
if (includeOpen) {
|
||||||
|
// retrieve all open pull requests
|
||||||
|
const openPullRequests = await this.getOpen(owner, repo, configuration.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
|
||||||
|
const baseBranches = configuration.base_branches
|
||||||
|
const baseBranchPatterns = baseBranches.map(baseBranch => {
|
||||||
|
return new RegExp(baseBranch.replace('\\\\', '\\'), 'gu')
|
||||||
|
})
|
||||||
|
|
||||||
|
// return only prs if the baseBranch is matching the configuration
|
||||||
|
const finalPrs = allPullRequests.filter(pr => {
|
||||||
|
if (baseBranches.length !== 0) {
|
||||||
|
return baseBranchPatterns.some(pattern => {
|
||||||
|
return pr.baseBranch.match(pattern) !== null
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
if (baseBranches.length !== 0) {
|
||||||
|
core.info(`ℹ️ Retrieved ${finalPrs.length} PRs for ${owner}/${repo} filtered by the 'base_branches' configuration.`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch reviewers only if enabled (requires an additional API request per PR)
|
||||||
|
if (fetchReviews || fetchReviewers) {
|
||||||
|
core.info(`ℹ️ Fetching reviews (or reviewers) was enabled`)
|
||||||
|
// update PR information with reviewers who approved
|
||||||
|
for (const pr of finalPrs) {
|
||||||
|
await this.getReviews(owner, repo, pr)
|
||||||
|
|
||||||
|
const reviews = pr.reviews
|
||||||
|
if (reviews && (reviews?.length || 0) > 0) {
|
||||||
|
core.info(`ℹ️ Retrieved ${reviews.length || 0} review(s) for PR ${owner}/${repo}/#${pr.number}`)
|
||||||
|
|
||||||
|
// backwards compatiblity
|
||||||
|
pr.approvedReviewers = reviews.filter(r => r.state === 'APPROVED').map(r => r.author)
|
||||||
|
} else {
|
||||||
|
core.debug(`No reviewer(s) for PR ${owner}/${repo}/#${pr.number}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
core.debug(`ℹ️ Fetching reviews (or reviewers) was disabled`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return [diffInfo, finalPrs]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortPrs(pullRequests: PullRequestInfo[]): PullRequestInfo[] {
|
function sortPrs(pullRequests: PullRequestInfo[]): PullRequestInfo[] {
|
||||||
@@ -227,8 +329,8 @@ export function retrieveProperty(pr: PullRequestInfo, property: Property, useCas
|
|||||||
}
|
}
|
||||||
|
|
||||||
// helper function to add a special open label to prs not merged.
|
// helper function to add a special open label to prs not merged.
|
||||||
function attachSpeciaLabels(status: 'open' | 'merged', labels: Set<string>): Set<string> {
|
function attachSpeciaLabels(status: 'open' | 'merged', labels: string[]): string[] {
|
||||||
labels.add(`--rcba-${status}`)
|
labels.push(`--rcba-${status}`)
|
||||||
return labels
|
return labels
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +345,7 @@ const mapPullRequest = (pr: PullData | Unpacked<PullsListData>, status: 'open' |
|
|||||||
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: attachSpeciaLabels(status, new Set(pr.labels?.map(lbl => lbl.name?.toLocaleLowerCase('en') || '') || [])),
|
labels: attachSpeciaLabels(status, 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 || '') || [],
|
||||||
|
|||||||
@@ -1,230 +0,0 @@
|
|||||||
import * as core from '@actions/core'
|
|
||||||
import {Commits, filterCommits, DiffInfo, DefaultDiffInfo} from './commits'
|
|
||||||
import {Configuration} from './configuration'
|
|
||||||
import {PullRequestInfo, PullRequests} from './pullRequests'
|
|
||||||
import {Octokit} from '@octokit/rest'
|
|
||||||
import {buildChangelog, replaceEmptyTemplate} from './transform'
|
|
||||||
import {failOrError} from './utils'
|
|
||||||
import {TagInfo} from './tags'
|
|
||||||
|
|
||||||
export interface ReleaseNotesOptions {
|
|
||||||
owner: string // the owner of the repository
|
|
||||||
repo: string // the repository
|
|
||||||
fromTag: TagInfo // the tag/ref to start from
|
|
||||||
toTag: TagInfo // 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
|
|
||||||
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
|
|
||||||
fetchReviews: boolean // defines if the action should fetch the reviews for the PR.
|
|
||||||
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`
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ReleaseNotes {
|
|
||||||
constructor(private octokit: Octokit, private options: ReleaseNotesOptions) {}
|
|
||||||
|
|
||||||
async pull(): Promise<string> {
|
|
||||||
let mergedPullRequests: PullRequestInfo[]
|
|
||||||
let diffInfo: DiffInfo
|
|
||||||
if (!this.options.commitMode) {
|
|
||||||
core.startGroup(`🚀 Load pull requests`)
|
|
||||||
|
|
||||||
const [info, prs] = await this.getMergedPullRequests(this.octokit)
|
|
||||||
mergedPullRequests = prs
|
|
||||||
diffInfo = info
|
|
||||||
|
|
||||||
// define the included PRs within this release as output
|
|
||||||
core.setOutput(
|
|
||||||
'pull_requests',
|
|
||||||
mergedPullRequests
|
|
||||||
.map(pr => {
|
|
||||||
return pr.number
|
|
||||||
})
|
|
||||||
.join(',')
|
|
||||||
)
|
|
||||||
|
|
||||||
core.endGroup()
|
|
||||||
} else {
|
|
||||||
core.startGroup(`🚀 Load commit history`)
|
|
||||||
core.info(`⚠️ Executing experimental commit mode`)
|
|
||||||
const [info, prs] = await this.generateCommitPRs(this.octokit)
|
|
||||||
mergedPullRequests = prs
|
|
||||||
diffInfo = info
|
|
||||||
core.endGroup()
|
|
||||||
}
|
|
||||||
|
|
||||||
core.setOutput('changed_files', diffInfo.changedFiles)
|
|
||||||
core.setOutput('additions', diffInfo.additions)
|
|
||||||
core.setOutput('deletions', diffInfo.deletions)
|
|
||||||
core.setOutput('changes', diffInfo.changes)
|
|
||||||
core.setOutput('commits', diffInfo.commits)
|
|
||||||
|
|
||||||
if (mergedPullRequests.length === 0) {
|
|
||||||
core.warning(`⚠️ No pull requests found`)
|
|
||||||
return replaceEmptyTemplate(this.options.configuration.empty_template, this.options)
|
|
||||||
}
|
|
||||||
|
|
||||||
core.startGroup('📦 Build changelog')
|
|
||||||
const resultChangelog = buildChangelog(diffInfo, mergedPullRequests, this.options)
|
|
||||||
core.endGroup()
|
|
||||||
return resultChangelog
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getCommitHistory(octokit: Octokit): Promise<DiffInfo> {
|
|
||||||
const {owner, repo, fromTag, toTag, failOnError} = this.options
|
|
||||||
core.info(`ℹ️ Comparing ${owner}/${repo} - '${fromTag.name}...${toTag.name}'`)
|
|
||||||
|
|
||||||
const commitsApi = new Commits(octokit)
|
|
||||||
let diffInfo: DiffInfo
|
|
||||||
try {
|
|
||||||
diffInfo = await commitsApi.getDiff(owner, repo, fromTag.name, toTag.name)
|
|
||||||
} catch (error) {
|
|
||||||
failOrError(`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, failOnError)
|
|
||||||
return DefaultDiffInfo
|
|
||||||
}
|
|
||||||
if (diffInfo.commitInfo.length === 0) {
|
|
||||||
core.warning(`⚠️ No commits found between - ${fromTag.name}...${toTag.name}`)
|
|
||||||
return DefaultDiffInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
return diffInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getMergedPullRequests(octokit: Octokit): Promise<[DiffInfo, PullRequestInfo[]]> {
|
|
||||||
const {owner, repo, includeOpen, fetchReviewers, fetchReviews, configuration} = this.options
|
|
||||||
|
|
||||||
const diffInfo = await this.getCommitHistory(octokit)
|
|
||||||
const commits = diffInfo.commitInfo
|
|
||||||
if (commits.length === 0) {
|
|
||||||
return [diffInfo, []]
|
|
||||||
}
|
|
||||||
|
|
||||||
const firstCommit = commits[0]
|
|
||||||
const lastCommit = commits[commits.length - 1]
|
|
||||||
let fromDate = firstCommit.date
|
|
||||||
const toDate = lastCommit.date
|
|
||||||
|
|
||||||
const maxDays = configuration.max_back_track_time_days
|
|
||||||
const maxFromDate = toDate.clone().subtract(maxDays, 'days')
|
|
||||||
if (maxFromDate.isAfter(fromDate)) {
|
|
||||||
core.info(`⚠️ Adjusted 'fromDate' to go max ${maxDays} back`)
|
|
||||||
fromDate = maxFromDate
|
|
||||||
}
|
|
||||||
|
|
||||||
core.info(`ℹ️ Fetching PRs between dates ${fromDate.toISOString()} to ${toDate.toISOString()} for ${owner}/${repo}`)
|
|
||||||
|
|
||||||
const pullRequestsApi = new PullRequests(octokit)
|
|
||||||
const pullRequests = await pullRequestsApi.getBetweenDates(owner, repo, fromDate, toDate, configuration.max_pull_requests)
|
|
||||||
|
|
||||||
core.info(`ℹ️ Retrieved ${pullRequests.length} PRs for ${owner}/${repo} in date range from API`)
|
|
||||||
|
|
||||||
const prCommits = filterCommits(commits, configuration.exclude_merge_branches)
|
|
||||||
|
|
||||||
core.info(`ℹ️ Retrieved ${prCommits.length} release commits for ${owner}/${repo}`)
|
|
||||||
|
|
||||||
// create array of commits for this release
|
|
||||||
const releaseCommitHashes = prCommits.map(commmit => {
|
|
||||||
return commmit.sha
|
|
||||||
})
|
|
||||||
|
|
||||||
// filter out pull requests not associated with this release
|
|
||||||
const mergedPullRequests = pullRequests.filter(pr => {
|
|
||||||
return releaseCommitHashes.includes(pr.mergeCommitSha)
|
|
||||||
})
|
|
||||||
|
|
||||||
core.info(`ℹ️ Retrieved ${mergedPullRequests.length} merged PRs for ${owner}/${repo}`)
|
|
||||||
|
|
||||||
let allPullRequests = mergedPullRequests
|
|
||||||
if (includeOpen) {
|
|
||||||
// retrieve all open pull requests
|
|
||||||
const openPullRequests = await pullRequestsApi.getOpen(owner, repo, configuration.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
|
|
||||||
const baseBranches = configuration.base_branches
|
|
||||||
const baseBranchPatterns = baseBranches.map(baseBranch => {
|
|
||||||
return new RegExp(baseBranch.replace('\\\\', '\\'), 'gu')
|
|
||||||
})
|
|
||||||
|
|
||||||
// return only prs if the baseBranch is matching the configuration
|
|
||||||
const finalPrs = allPullRequests.filter(pr => {
|
|
||||||
if (baseBranches.length !== 0) {
|
|
||||||
return baseBranchPatterns.some(pattern => {
|
|
||||||
return pr.baseBranch.match(pattern) !== null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
if (baseBranches.length !== 0) {
|
|
||||||
core.info(`ℹ️ Retrieved ${finalPrs.length} PRs for ${owner}/${repo} filtered by the 'base_branches' configuration.`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch reviewers only if enabled (requires an additional API request per PR)
|
|
||||||
if (fetchReviews || fetchReviewers) {
|
|
||||||
core.info(`ℹ️ Fetching reviews (or reviewers) was enabled`)
|
|
||||||
// update PR information with reviewers who approved
|
|
||||||
for (const pr of finalPrs) {
|
|
||||||
await pullRequestsApi.getReviews(owner, repo, pr)
|
|
||||||
|
|
||||||
const reviews = pr.reviews
|
|
||||||
if (reviews && (reviews?.length || 0) > 0) {
|
|
||||||
core.info(`ℹ️ Retrieved ${reviews.length || 0} review(s) for PR ${owner}/${repo}/#${pr.number}`)
|
|
||||||
|
|
||||||
// backwards compatiblity
|
|
||||||
pr.approvedReviewers = reviews.filter(r => r.state === 'APPROVED').map(r => r.author)
|
|
||||||
} else {
|
|
||||||
core.debug(`No reviewer(s) for PR ${owner}/${repo}/#${pr.number}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
core.debug(`ℹ️ Fetching reviews (or reviewers) was disabled`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return [diffInfo, finalPrs]
|
|
||||||
}
|
|
||||||
|
|
||||||
private async generateCommitPRs(octokit: Octokit): Promise<[DiffInfo, PullRequestInfo[]]> {
|
|
||||||
const {owner, repo, configuration} = this.options
|
|
||||||
|
|
||||||
const diffInfo = await this.getCommitHistory(octokit)
|
|
||||||
const commits = diffInfo.commitInfo
|
|
||||||
if (commits.length === 0) {
|
|
||||||
return [diffInfo, []]
|
|
||||||
}
|
|
||||||
|
|
||||||
const prCommits = filterCommits(commits, configuration.exclude_merge_branches)
|
|
||||||
|
|
||||||
core.info(`ℹ️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`)
|
|
||||||
|
|
||||||
const prs = prCommits.map(function (commit): PullRequestInfo {
|
|
||||||
return {
|
|
||||||
number: 0,
|
|
||||||
title: commit.summary,
|
|
||||||
htmlURL: '',
|
|
||||||
baseBranch: '',
|
|
||||||
createdAt: commit.date,
|
|
||||||
mergedAt: commit.date,
|
|
||||||
mergeCommitSha: commit.sha,
|
|
||||||
author: commit.author || '',
|
|
||||||
repoName: '',
|
|
||||||
labels: new Set(),
|
|
||||||
milestone: '',
|
|
||||||
body: commit.message || '',
|
|
||||||
assignees: [],
|
|
||||||
requestedReviewers: [],
|
|
||||||
approvedReviewers: [],
|
|
||||||
status: 'merged'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return [diffInfo, prs]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+138
-6
@@ -1,10 +1,32 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {Configuration} from './configuration'
|
import {Configuration} from './configuration'
|
||||||
import {Octokit} from '@octokit/rest'
|
import {Octokit} from '@octokit/rest'
|
||||||
import {ReleaseNotes} from './releaseNotes'
|
import {TagInfo, Tags} from './tags'
|
||||||
import {Tags} from './tags'
|
import {checkExportedData, failOrError} from './utils'
|
||||||
import {failOrError} from './utils'
|
|
||||||
import {HttpsProxyAgent} from 'https-proxy-agent'
|
import {HttpsProxyAgent} from 'https-proxy-agent'
|
||||||
|
import {PullRequestInfo, PullRequests} from './pullRequests'
|
||||||
|
import {Commits, DiffInfo} from './commits'
|
||||||
|
import {buildChangelog} from './transform'
|
||||||
|
|
||||||
|
export interface ReleaseNotesOptions {
|
||||||
|
owner: string // the owner of the repository
|
||||||
|
repo: string // the repository
|
||||||
|
fromTag: TagInfo // the tag/ref to start from
|
||||||
|
toTag: TagInfo // 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
|
||||||
|
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
|
||||||
|
fetchReviews: boolean // defines if the action should fetch the reviews for the PR.
|
||||||
|
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`
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReleaseNotesData {
|
||||||
|
diffInfo: DiffInfo
|
||||||
|
mergedPullRequests: PullRequestInfo[]
|
||||||
|
options: ReleaseNotesOptions
|
||||||
|
}
|
||||||
|
|
||||||
export class ReleaseNotesBuilder {
|
export class ReleaseNotesBuilder {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -21,11 +43,15 @@ export class ReleaseNotesBuilder {
|
|||||||
private fetchReviewers: boolean = false,
|
private fetchReviewers: boolean = false,
|
||||||
private fetchReleaseInformation: boolean = false,
|
private fetchReleaseInformation: boolean = false,
|
||||||
private fetchReviews: boolean = false,
|
private fetchReviews: boolean = false,
|
||||||
private commitMode: boolean,
|
private commitMode: boolean = false,
|
||||||
|
private exportCollected: boolean = false,
|
||||||
|
private exportOnly: boolean = false,
|
||||||
private configuration: Configuration
|
private configuration: Configuration
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async build(): Promise<string | null> {
|
async build(): Promise<string | null> {
|
||||||
|
let releaseNotesData = checkExportedData()
|
||||||
|
if (releaseNotesData == null) {
|
||||||
if (!this.owner) {
|
if (!this.owner) {
|
||||||
failOrError(`💥 Missing or couldn't resolve 'owner'`, this.failOnError)
|
failOrError(`💥 Missing or couldn't resolve 'owner'`, this.failOnError)
|
||||||
return null
|
return null
|
||||||
@@ -122,8 +148,114 @@ export class ReleaseNotesBuilder {
|
|||||||
commitMode: this.commitMode,
|
commitMode: this.commitMode,
|
||||||
configuration: this.configuration
|
configuration: this.configuration
|
||||||
}
|
}
|
||||||
const releaseNotes = new ReleaseNotes(octokit, options)
|
|
||||||
|
|
||||||
return await releaseNotes.pull()
|
releaseNotesData = await pullData(octokit, options, this.exportCollected, this.exportOnly)
|
||||||
|
} else {
|
||||||
|
core.info(`ℹ️ Retrieved previously exported collected data`)
|
||||||
|
|
||||||
|
// merge input with options (in case some data was updated)
|
||||||
|
const diffInfo = releaseNotesData.diffInfo
|
||||||
|
const mergedPullRequests = releaseNotesData.mergedPullRequests
|
||||||
|
const orgOptions = releaseNotesData.options
|
||||||
|
|
||||||
|
// merge fromTag info with provided info || otherwise use cached info
|
||||||
|
const fromTag: TagInfo = orgOptions.fromTag
|
||||||
|
if (this.fromTag != null) {
|
||||||
|
fromTag.name = this.fromTag
|
||||||
|
}
|
||||||
|
const toTag: TagInfo = orgOptions.toTag
|
||||||
|
if (this.toTag != null) {
|
||||||
|
toTag.name = this.toTag
|
||||||
|
}
|
||||||
|
|
||||||
|
// merge provided values with previous options (prefer provided)
|
||||||
|
const options: ReleaseNotesOptions = {
|
||||||
|
owner: this.owner || orgOptions.owner,
|
||||||
|
repo: this.repo || orgOptions.repo,
|
||||||
|
fromTag,
|
||||||
|
toTag,
|
||||||
|
includeOpen: this.includeOpen || orgOptions.includeOpen,
|
||||||
|
failOnError: this.failOnError || orgOptions.failOnError,
|
||||||
|
fetchReviewers: this.fetchReviewers || orgOptions.fetchReviewers,
|
||||||
|
fetchReleaseInformation: this.fetchReleaseInformation || orgOptions.fetchReleaseInformation,
|
||||||
|
fetchReviews: this.fetchReviews || orgOptions.fetchReviews,
|
||||||
|
commitMode: this.commitMode || orgOptions.commitMode,
|
||||||
|
configuration: this.configuration || orgOptions.configuration
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseNotesData = {
|
||||||
|
diffInfo,
|
||||||
|
mergedPullRequests,
|
||||||
|
options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (releaseNotesData != null) {
|
||||||
|
return buildChangelog(releaseNotesData.diffInfo, releaseNotesData.mergedPullRequests, releaseNotesData.options)
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function pullData(
|
||||||
|
octokit: Octokit,
|
||||||
|
options: ReleaseNotesOptions,
|
||||||
|
exportCollected: boolean,
|
||||||
|
exportOnly: boolean
|
||||||
|
): Promise<ReleaseNotesData | null> {
|
||||||
|
let mergedPullRequests: PullRequestInfo[]
|
||||||
|
let diffInfo: DiffInfo
|
||||||
|
|
||||||
|
const commitsApi = new Commits(octokit)
|
||||||
|
if (!options.commitMode) {
|
||||||
|
core.startGroup(`🚀 Load pull requests`)
|
||||||
|
const pullRequestsApi = new PullRequests(octokit, commitsApi)
|
||||||
|
const [info, prs] = await pullRequestsApi.getMergedPullRequests(options)
|
||||||
|
mergedPullRequests = prs
|
||||||
|
diffInfo = info
|
||||||
|
} else {
|
||||||
|
core.startGroup(`🚀 Load commit history`)
|
||||||
|
core.info(`⚠️ Executing experimental commit mode`)
|
||||||
|
const [info, prs] = await commitsApi.generateCommitPRs(options)
|
||||||
|
mergedPullRequests = prs
|
||||||
|
diffInfo = info
|
||||||
|
}
|
||||||
|
|
||||||
|
// define the included PRs within this release as output
|
||||||
|
core.setOutput(
|
||||||
|
'pull_requests',
|
||||||
|
mergedPullRequests
|
||||||
|
.map(pr => {
|
||||||
|
return pr.number
|
||||||
|
})
|
||||||
|
.join(',')
|
||||||
|
)
|
||||||
|
core.setOutput('changed_files', diffInfo.changedFiles)
|
||||||
|
core.setOutput('additions', diffInfo.additions)
|
||||||
|
core.setOutput('deletions', diffInfo.deletions)
|
||||||
|
core.setOutput('changes', diffInfo.changes)
|
||||||
|
core.setOutput('commits', diffInfo.commits)
|
||||||
|
|
||||||
|
if (exportCollected) {
|
||||||
|
core.info('📦 Exporting collected data')
|
||||||
|
core.exportVariable(`RCBA_EXPORT_diffInfo`, JSON.stringify(diffInfo))
|
||||||
|
//fs.writeFileSync(path.resolve('diffInfo.json'), JSON.stringify(diffInfo))
|
||||||
|
core.exportVariable(`RCBA_EXPORT_mergedPullRequests`, JSON.stringify(mergedPullRequests))
|
||||||
|
//fs.writeFileSync(path.resolve('mergedPullRequests.json'), JSON.stringify(mergedPullRequests))
|
||||||
|
core.exportVariable(`RCBA_EXPORT_options`, JSON.stringify(options))
|
||||||
|
//fs.writeFileSync(path.resolve('options.json'), JSON.stringify(options))
|
||||||
|
|
||||||
|
if (exportOnly) {
|
||||||
|
core.endGroup()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core.endGroup()
|
||||||
|
|
||||||
|
return {
|
||||||
|
diffInfo,
|
||||||
|
mergedPullRequests,
|
||||||
|
options
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-8
@@ -1,14 +1,22 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {Category, Configuration, Placeholder, Property, Transformer} from './configuration'
|
import {Category, Configuration, Placeholder, Property, Transformer} from './configuration'
|
||||||
import {CommentInfo, EMPTY_COMMENT_INFO, PullRequestInfo, retrieveProperty, sortPullRequests} from './pullRequests'
|
import {CommentInfo, EMPTY_COMMENT_INFO, PullRequestInfo, retrieveProperty, sortPullRequests} from './pullRequests'
|
||||||
import {ReleaseNotesOptions} from './releaseNotes'
|
import {ReleaseNotesOptions} from './releaseNotesBuilder'
|
||||||
import {DiffInfo} from './commits'
|
import {DiffInfo} from './commits'
|
||||||
import {createOrSet, haveCommonElements, haveEveryElements} from './utils'
|
import {createOrSet, haveCommonElementsArr, haveEveryElementsArr} from './utils'
|
||||||
import {matchesRules, RegexTransformer, validateTransformer} from './regexUtils'
|
import {matchesRules, RegexTransformer, validateTransformer} from './regexUtils'
|
||||||
|
|
||||||
const EMPTY_MAP = new Map<string, string>()
|
const EMPTY_MAP = new Map<string, string>()
|
||||||
|
|
||||||
export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], options: ReleaseNotesOptions): string {
|
export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], options: ReleaseNotesOptions): string {
|
||||||
|
core.startGroup('📦 Build changelog')
|
||||||
|
if (prs.length === 0) {
|
||||||
|
core.warning(`⚠️ No pull requests found`)
|
||||||
|
const result = replaceEmptyTemplate(options.configuration.empty_template, options)
|
||||||
|
core.endGroup()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// sort to target order
|
// sort to target order
|
||||||
const config = options.configuration
|
const config = options.configuration
|
||||||
const sort = config.sort
|
const sort = config.sort
|
||||||
@@ -49,7 +57,7 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
|
|||||||
const extracted = extractValues(pr, extractor, 'label_extractor')
|
const extracted = extractValues(pr, extractor, 'label_extractor')
|
||||||
if (extracted !== null) {
|
if (extracted !== null) {
|
||||||
for (const label of extracted) {
|
for (const label of extracted) {
|
||||||
pr.labels.add(label)
|
pr.labels.push(label)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (core.isDebug()) {
|
if (core.isDebug()) {
|
||||||
@@ -92,7 +100,7 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
|
|||||||
// bring elements in order
|
// bring elements in order
|
||||||
for (const [pr, body] of transformedMap) {
|
for (const [pr, body] of transformedMap) {
|
||||||
if (
|
if (
|
||||||
haveCommonElements(
|
haveCommonElementsArr(
|
||||||
ignoredLabels.map(lbl => lbl.toLocaleLowerCase('en')),
|
ignoredLabels.map(lbl => lbl.toLocaleLowerCase('en')),
|
||||||
pr.labels
|
pr.labels
|
||||||
)
|
)
|
||||||
@@ -111,7 +119,7 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
|
|||||||
// check if any exclude label matches
|
// check if any exclude label matches
|
||||||
if (category.exclude_labels !== undefined) {
|
if (category.exclude_labels !== undefined) {
|
||||||
if (
|
if (
|
||||||
haveCommonElements(
|
haveCommonElementsArr(
|
||||||
category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
||||||
pr.labels
|
pr.labels
|
||||||
)
|
)
|
||||||
@@ -128,7 +136,7 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
|
|||||||
// validate for an exhaustive match (e.g. every provided rule applies)
|
// validate for an exhaustive match (e.g. every provided rule applies)
|
||||||
if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) {
|
if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) {
|
||||||
if (category.labels !== undefined) {
|
if (category.labels !== undefined) {
|
||||||
matched = haveEveryElements(
|
matched = haveEveryElementsArr(
|
||||||
category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
||||||
pr.labels
|
pr.labels
|
||||||
)
|
)
|
||||||
@@ -144,7 +152,7 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
|
|||||||
// if not exhaustive, do individual matches
|
// if not exhaustive, do individual matches
|
||||||
if (category.labels !== undefined) {
|
if (category.labels !== undefined) {
|
||||||
// check if either any of the labels applies
|
// check if either any of the labels applies
|
||||||
matched = haveCommonElements(
|
matched = haveCommonElementsArr(
|
||||||
category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
||||||
pr.labels
|
pr.labels
|
||||||
)
|
)
|
||||||
@@ -181,7 +189,8 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
|
|||||||
|
|
||||||
// serialize and provide the categorized content as json
|
// serialize and provide the categorized content as json
|
||||||
const transformedCategorized = Array.from(categorized).reduce(
|
const transformedCategorized = Array.from(categorized).reduce(
|
||||||
(obj, [key, value]) => Object.assign(obj, {[key.key || key.title]: value}), {}
|
(obj, [key, value]) => Object.assign(obj, {[key.key || key.title]: value}),
|
||||||
|
{}
|
||||||
)
|
)
|
||||||
core.setOutput('categorized', JSON.stringify(transformedCategorized))
|
core.setOutput('categorized', JSON.stringify(transformedCategorized))
|
||||||
|
|
||||||
@@ -273,6 +282,7 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
|
|||||||
transformedChangelog = replacePrPlaceholders(transformedChangelog, placeholderPrMap, config)
|
transformedChangelog = replacePrPlaceholders(transformedChangelog, placeholderPrMap, config)
|
||||||
transformedChangelog = cleanupPrPlaceholders(transformedChangelog, placeholders)
|
transformedChangelog = cleanupPrPlaceholders(transformedChangelog, placeholders)
|
||||||
core.info(`ℹ️ Filled template`)
|
core.info(`ℹ️ Filled template`)
|
||||||
|
core.endGroup()
|
||||||
return transformedChangelog
|
return transformedChangelog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ import * as core from '@actions/core'
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import {Configuration, DefaultConfiguration} from './configuration'
|
import {Configuration, DefaultConfiguration} from './configuration'
|
||||||
|
import {ReleaseNotesData, ReleaseNotesOptions} from './releaseNotesBuilder'
|
||||||
|
import {DiffInfo} from './commits'
|
||||||
|
import {PullRequestInfo} from './pullRequests'
|
||||||
|
import moment from 'moment'
|
||||||
/**
|
/**
|
||||||
* Resolves the repository path, relatively to the GITHUB_WORKSPACE
|
* Resolves the repository path, relatively to the GITHUB_WORKSPACE
|
||||||
*/
|
*/
|
||||||
@@ -32,6 +36,45 @@ export function failOrError(message: string | Error, failOnError: boolean): void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the exported information from a previous run of the `release-changelog-builder-action`.
|
||||||
|
* If available, return a [ReleaseNotesData].
|
||||||
|
*/
|
||||||
|
export function checkExportedData(): ReleaseNotesData | null {
|
||||||
|
const rawDiffInfo = process.env[`RCBA_EXPORT_diffInfo`]
|
||||||
|
const rawMergedPullRequests = process.env[`RCBA_EXPORT_mergedPullRequests`]
|
||||||
|
const rawOptions = process.env[`RCBA_EXPORT_options`]
|
||||||
|
|
||||||
|
if (rawDiffInfo && rawMergedPullRequests && rawOptions) {
|
||||||
|
const diffInfo: DiffInfo = JSON.parse(rawDiffInfo)
|
||||||
|
const mergedPullRequests: PullRequestInfo[] = JSON.parse(rawMergedPullRequests)
|
||||||
|
|
||||||
|
for (const pr of mergedPullRequests) {
|
||||||
|
pr.createdAt = moment(pr.createdAt)
|
||||||
|
if (pr.mergedAt) {
|
||||||
|
pr.mergedAt = moment(pr.mergedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pr.reviews) {
|
||||||
|
for (const review of pr.reviews) {
|
||||||
|
if (review.submittedAt) {
|
||||||
|
review.submittedAt = moment(review.submittedAt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const options: ReleaseNotesOptions = JSON.parse(rawOptions)
|
||||||
|
return {
|
||||||
|
diffInfo,
|
||||||
|
mergedPullRequests,
|
||||||
|
options
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the configuration given the file path, if not found it will fallback to the `DefaultConfiguration`
|
* Retrieves the configuration given the file path, if not found it will fallback to the `DefaultConfiguration`
|
||||||
*/
|
*/
|
||||||
@@ -172,6 +215,14 @@ export function haveCommonElements(arr1: string[], arr2: Set<string>): boolean {
|
|||||||
return arr1.some(item => arr2.has(item))
|
return arr1.some(item => arr2.has(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function haveCommonElementsArr(arr1: string[], arr2: string[]): boolean {
|
||||||
|
return haveCommonElements(arr1, new Set(arr2))
|
||||||
|
}
|
||||||
|
|
||||||
export function haveEveryElements(arr1: string[], arr2: Set<string>): boolean {
|
export function haveEveryElements(arr1: string[], arr2: Set<string>): boolean {
|
||||||
return arr1.every(item => arr2.has(item))
|
return arr1.every(item => arr2.has(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function haveEveryElementsArr(arr1: string[], arr2: string[]): boolean {
|
||||||
|
return haveEveryElements(arr1, new Set(arr2))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user