- move pr collection into npm module
(publish without any furhter notes or docs) - refactor action to use npm dependency
This commit is contained in:
@@ -33,10 +33,20 @@ jobs:
|
||||
node-version: 16.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
run: |
|
||||
cd pr-collector
|
||||
npm ci
|
||||
|
||||
cd ..
|
||||
npm ci
|
||||
|
||||
- name: Rebuild the dist/ directory
|
||||
run: |
|
||||
cd pr-collector
|
||||
npm run build
|
||||
npm run package
|
||||
|
||||
cd ..
|
||||
npm run build
|
||||
npm run package
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ jobs:
|
||||
|
||||
- name: Run NPM
|
||||
run: |
|
||||
cd pr-collector
|
||||
npm run all
|
||||
|
||||
cd ..
|
||||
npm run all
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -97,3 +97,6 @@ Thumbs.db
|
||||
# Ignore built ts files
|
||||
__tests__/runner/*
|
||||
lib/**/*
|
||||
|
||||
lib
|
||||
pr-collector/dist
|
||||
@@ -13,5 +13,7 @@ it('Configurations are merged correctly', async () => {
|
||||
const mergedConfiguration = mergeConfiguration(configurationJson, configurationFile)
|
||||
|
||||
console.log(mergedConfiguration)
|
||||
expect(JSON.stringify(mergedConfiguration)).toEqual(`{\"max_tags_to_fetch\":200,\"max_pull_requests\":1000,\"max_back_track_time_days\":1000,\"exclude_merge_branches\":[],\"sort\":\"DESC\",\"template\":\"$\{\{CHANGELOG}}\",\"pr_template\":\"- $\{\{TITLE}}\\n - PR: #$\{\{NUMBER}}\",\"empty_template\":\"- no magic changes\",\"categories\":[{\"title\":\"## 🚀 Features\",\"labels\":[\"feature\"]},{\"title\":\"## 🐛 Fixes\",\"labels\":[\"fix\"]},{\"title\":\"## 🧪 Tests\",\"labels\":[\"test\"]}],\"ignore_labels\":[\"ignore\"],\"label_extractor\":[],\"transformers\":[],\"tag_resolver\":{\"method\":\"semver\"},\"base_branches\":[],\"custom_placeholders\":[],\"trim_values\":true}`)
|
||||
expect(JSON.stringify(mergedConfiguration)).toEqual(
|
||||
`{\"max_tags_to_fetch\":200,\"max_pull_requests\":1000,\"max_back_track_time_days\":1000,\"exclude_merge_branches\":[],\"sort\":\"DESC\",\"template\":\"$\{\{CHANGELOG}}\",\"pr_template\":\"- $\{\{TITLE}}\\n - PR: #$\{\{NUMBER}}\",\"empty_template\":\"- no magic changes\",\"categories\":[{\"title\":\"## 🚀 Features\",\"labels\":[\"feature\"]},{\"title\":\"## 🐛 Fixes\",\"labels\":[\"fix\"]},{\"title\":\"## 🧪 Tests\",\"labels\":[\"test\"]}],\"ignore_labels\":[\"ignore\"],\"label_extractor\":[],\"transformers\":[],\"tag_resolver\":{\"method\":\"semver\"},\"base_branches\":[],\"custom_placeholders\":[],\"trim_values\":true}`
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {mergeConfiguration, resolveConfiguration} from '../src/utils'
|
||||
import {pullData} from '../src/releaseNotesBuilder'
|
||||
import {Octokit} from '@octokit/rest'
|
||||
import { buildChangelog } from '../src/transform'
|
||||
import {buildChangelog} from '../src/transform'
|
||||
|
||||
jest.setTimeout(180000)
|
||||
|
||||
@@ -13,7 +13,9 @@ const octokit = new Octokit({
|
||||
it('Should have empty changelog (tags)', async () => {
|
||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs/configuration.json'))
|
||||
|
||||
const data = await pullData(octokit, {
|
||||
const data = await pullData(
|
||||
octokit,
|
||||
{
|
||||
owner: 'mikepenz',
|
||||
repo: 'release-changelog-builder-action',
|
||||
fromTag: {name: 'v0.0.1'},
|
||||
@@ -25,7 +27,10 @@ it('Should have empty changelog (tags)', async () => {
|
||||
fetchReviews: false,
|
||||
commitMode: false,
|
||||
configuration
|
||||
}, false, false)
|
||||
},
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
||||
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||
console.log(changeLog)
|
||||
@@ -34,7 +39,9 @@ it('Should have empty changelog (tags)', async () => {
|
||||
|
||||
it('Should match generated changelog (tags)', async () => {
|
||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs/configuration.json'))
|
||||
const data = await pullData(octokit, {
|
||||
const data = await pullData(
|
||||
octokit,
|
||||
{
|
||||
owner: 'mikepenz',
|
||||
repo: 'release-changelog-builder-action',
|
||||
fromTag: {name: 'v0.0.1'},
|
||||
@@ -46,7 +53,10 @@ it('Should match generated changelog (tags)', async () => {
|
||||
fetchReviews: false,
|
||||
commitMode: false,
|
||||
configuration
|
||||
}, false, false)
|
||||
},
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
||||
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||
console.log(changeLog)
|
||||
@@ -60,7 +70,9 @@ it('Should match generated changelog (tags)', async () => {
|
||||
|
||||
it('Should match generated changelog (refs)', async () => {
|
||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_all_placeholders.json'))
|
||||
const data = await pullData(octokit, {
|
||||
const data = await pullData(
|
||||
octokit,
|
||||
{
|
||||
owner: 'mikepenz',
|
||||
repo: 'release-changelog-builder-action',
|
||||
fromTag: {name: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3'},
|
||||
@@ -72,7 +84,10 @@ it('Should match generated changelog (refs)', async () => {
|
||||
fetchReviews: false,
|
||||
commitMode: false,
|
||||
configuration
|
||||
}, false, false)
|
||||
},
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
||||
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||
console.log(changeLog)
|
||||
@@ -94,7 +109,9 @@ nhoelzl
|
||||
|
||||
it('Should match generated changelog and replace all occurrences (refs)', async () => {
|
||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_replace_all_placeholders.json'))
|
||||
const data = await pullData(octokit, {
|
||||
const data = await pullData(
|
||||
octokit,
|
||||
{
|
||||
owner: 'mikepenz',
|
||||
repo: 'release-changelog-builder-action',
|
||||
fromTag: {name: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3'},
|
||||
@@ -106,7 +123,10 @@ it('Should match generated changelog and replace all occurrences (refs)', async
|
||||
fetchReviews: false,
|
||||
commitMode: false,
|
||||
configuration
|
||||
}, false, false)
|
||||
},
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
||||
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||
console.log(changeLog)
|
||||
@@ -130,7 +150,9 @@ nhoelzl
|
||||
|
||||
it('Should match ordered ASC', async () => {
|
||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_asc.json'))
|
||||
const data = await pullData(octokit, {
|
||||
const data = await pullData(
|
||||
octokit,
|
||||
{
|
||||
owner: 'mikepenz',
|
||||
repo: 'release-changelog-builder-action',
|
||||
fromTag: {name: 'v0.3.0'},
|
||||
@@ -142,7 +164,10 @@ it('Should match ordered ASC', async () => {
|
||||
fetchReviews: false,
|
||||
commitMode: false,
|
||||
configuration
|
||||
}, false, false)
|
||||
},
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
||||
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||
console.log(changeLog)
|
||||
@@ -151,7 +176,9 @@ it('Should match ordered ASC', async () => {
|
||||
|
||||
it('Should match ordered DESC', async () => {
|
||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_desc.json'))
|
||||
const data = await pullData(octokit, {
|
||||
const data = await pullData(
|
||||
octokit,
|
||||
{
|
||||
owner: 'mikepenz',
|
||||
repo: 'release-changelog-builder-action',
|
||||
fromTag: {name: 'v0.3.0'},
|
||||
@@ -163,7 +190,10 @@ it('Should match ordered DESC', async () => {
|
||||
fetchReviews: false,
|
||||
commitMode: false,
|
||||
configuration
|
||||
}, false, false)
|
||||
},
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
||||
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||
console.log(changeLog)
|
||||
@@ -172,7 +202,9 @@ it('Should match ordered DESC', async () => {
|
||||
|
||||
it('Should match ordered by title ASC', async () => {
|
||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_sort_title_asc.json'))
|
||||
const data = await pullData(octokit, {
|
||||
const data = await pullData(
|
||||
octokit,
|
||||
{
|
||||
owner: 'mikepenz',
|
||||
repo: 'release-changelog-builder-action',
|
||||
fromTag: {name: 'v0.3.0'},
|
||||
@@ -184,7 +216,10 @@ it('Should match ordered by title ASC', async () => {
|
||||
fetchReviews: false,
|
||||
commitMode: false,
|
||||
configuration
|
||||
}, false, false)
|
||||
},
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
||||
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||
console.log(changeLog)
|
||||
@@ -195,7 +230,9 @@ it('Should match ordered by title ASC', async () => {
|
||||
|
||||
it('Should match ordered by title DESC', async () => {
|
||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_sort_title_desc.json'))
|
||||
const data = await pullData(octokit, {
|
||||
const data = await pullData(
|
||||
octokit,
|
||||
{
|
||||
owner: 'mikepenz',
|
||||
repo: 'release-changelog-builder-action',
|
||||
fromTag: {name: 'v0.3.0'},
|
||||
@@ -207,7 +244,10 @@ it('Should match ordered by title DESC', async () => {
|
||||
fetchReviews: false,
|
||||
commitMode: false,
|
||||
configuration
|
||||
}, false, false)
|
||||
},
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
||||
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||
console.log(changeLog)
|
||||
@@ -218,7 +258,9 @@ it('Should match ordered by title DESC', async () => {
|
||||
|
||||
it('Should ignore PRs not merged into develop branch', async () => {
|
||||
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_base_branches_develop.json'))
|
||||
const data = await pullData(octokit, {
|
||||
const data = await pullData(
|
||||
octokit,
|
||||
{
|
||||
owner: 'mikepenz',
|
||||
repo: 'release-changelog-builder-action',
|
||||
fromTag: {name: 'v1.3.1'},
|
||||
@@ -230,7 +272,10 @@ it('Should ignore PRs not merged into develop branch', async () => {
|
||||
fetchReviews: false,
|
||||
commitMode: false,
|
||||
configuration
|
||||
}, false, false)
|
||||
},
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
||||
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||
console.log(changeLog)
|
||||
@@ -239,7 +284,9 @@ it('Should ignore PRs not merged into develop 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 data = await pullData(octokit, {
|
||||
const data = await pullData(
|
||||
octokit,
|
||||
{
|
||||
owner: 'mikepenz',
|
||||
repo: 'release-changelog-builder-action',
|
||||
fromTag: {name: 'v1.3.1'},
|
||||
@@ -251,7 +298,10 @@ it('Should ignore PRs not merged into main branch', async () => {
|
||||
fetchReviews: false,
|
||||
commitMode: false,
|
||||
configuration
|
||||
}, false, false)
|
||||
},
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
||||
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
|
||||
console.log(changeLog)
|
||||
|
||||
@@ -23,9 +23,7 @@ it('Should order tags correctly using semver', async () => {
|
||||
})
|
||||
.join(',')
|
||||
|
||||
expect(sorted).toStrictEqual(
|
||||
`2020.4.0,2020.4.0-rc02,2020.3.2,v2020.3.1,2020.3.1-rc03,2020.3.1-rc01,2020.3.1-b01,v2020.3.0`
|
||||
)
|
||||
expect(sorted).toStrictEqual(`2020.4.0,2020.4.0-rc02,2020.3.2,v2020.3.1,2020.3.1-rc03,2020.3.1-rc01,2020.3.1-b01,v2020.3.0`)
|
||||
})
|
||||
|
||||
it('Should order tags correctly using semver', async () => {
|
||||
@@ -54,9 +52,7 @@ it('Should order tags correctly using semver', async () => {
|
||||
})
|
||||
.join(',')
|
||||
|
||||
expect(sorted).toStrictEqual(
|
||||
`1000.0.0,100.0.0,20.0.2,10.1.0,10.1.0-2,10.0.0,2.0.0,1.0.0,1.0.0-a01,0.1.0,0.1.0-b01,0.0.1,0.0.1-rc01`
|
||||
)
|
||||
expect(sorted).toStrictEqual(`1000.0.0,100.0.0,20.0.2,10.1.0,10.1.0-2,10.0.0,2.0.0,1.0.0,1.0.0-a01,0.1.0,0.1.0-b01,0.0.1,0.0.1-rc01`)
|
||||
})
|
||||
|
||||
it('Should order tags alphabetical', async () => {
|
||||
@@ -85,9 +81,7 @@ it('Should order tags alphabetical', async () => {
|
||||
})
|
||||
.join(',')
|
||||
|
||||
expect(sorted).toStrictEqual(
|
||||
`a,20.0.2,2.0.0,1000.0.0,10.1.0,10.1.0-2,10.0.0,1.0.0,1.0.0-a01,v1,0.1.0-b01,0.0.1,0.0.1-rc01`
|
||||
)
|
||||
expect(sorted).toStrictEqual(`a,20.0.2,2.0.0,1000.0.0,10.1.0,10.1.0-2,10.0.0,1.0.0,1.0.0-a01,v1,0.1.0-b01,0.0.1,0.0.1-rc01`)
|
||||
})
|
||||
|
||||
it('Should filter tags correctly using the regex', async () => {
|
||||
|
||||
+17
-21
@@ -329,8 +329,8 @@ openPullRequestsWithLabels.push(
|
||||
requestedReviewers: [],
|
||||
approvedReviewers: [],
|
||||
status: 'open'
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
number: 7,
|
||||
title: 'Still pending open pull request',
|
||||
htmlURL: '',
|
||||
@@ -347,7 +347,7 @@ openPullRequestsWithLabels.push(
|
||||
requestedReviewers: [],
|
||||
approvedReviewers: [],
|
||||
status: 'open'
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
it('Match multiple labels exhaustive for category', async () => {
|
||||
@@ -457,9 +457,7 @@ it('Release Diff', async () => {
|
||||
configuration: customConfig
|
||||
})
|
||||
|
||||
expect(resultChangelog).toStrictEqual(
|
||||
`https://github.com/mikepenz/release-changelog-builder-action/compare/v2.8.0...v2.8.1\n`
|
||||
)
|
||||
expect(resultChangelog).toStrictEqual(`https://github.com/mikepenz/release-changelog-builder-action/compare/v2.8.0...v2.8.1\n`)
|
||||
})
|
||||
|
||||
it('Use exclude labels to not include a PR within a category.', async () => {
|
||||
@@ -532,7 +530,6 @@ it('Extract custom placeholder from PR body and replace in global template', asy
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
it('Use Rules to include a PR within a Category.', async () => {
|
||||
const customConfig = Object.assign({}, DefaultConfiguration)
|
||||
customConfig.categories = [
|
||||
@@ -542,12 +539,12 @@ it('Use Rules to include a PR within a Category.', async () => {
|
||||
exclude_labels: ['Fix'],
|
||||
rules: [
|
||||
{
|
||||
pattern: "\[ABC-1234\]",
|
||||
on_property: "title"
|
||||
pattern: '[ABC-1234]',
|
||||
on_property: 'title'
|
||||
},
|
||||
{
|
||||
pattern: "merged",
|
||||
on_property: "status"
|
||||
pattern: 'merged',
|
||||
on_property: 'status'
|
||||
}
|
||||
],
|
||||
exhaustive: true
|
||||
@@ -568,8 +565,8 @@ it('Use Rules to get all open PRs in a Category.', async () => {
|
||||
title: '## Open PRs only',
|
||||
rules: [
|
||||
{
|
||||
pattern: "open",
|
||||
on_property: "status"
|
||||
pattern: 'open',
|
||||
on_property: 'status'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -577,7 +574,6 @@ it('Use Rules to get all open PRs in a Category.', async () => {
|
||||
expect(buildChangelogTest(customConfig, prs)).toStrictEqual(`## Open PRs only\n\n- Still pending open pull request\n - PR: #6\n\n`)
|
||||
})
|
||||
|
||||
|
||||
it('Use Rules to get current open PR and merged categorised.', async () => {
|
||||
let prs = Array.from(pullRequestsWithLabels)
|
||||
prs = prs.concat(Array.from(openPullRequestsWithLabels))
|
||||
@@ -599,7 +595,8 @@ it('Use Rules to get current open PR and merged categorised.', async () => {
|
||||
],
|
||||
exhaustive: true,
|
||||
exhaustive_rules: false
|
||||
},{
|
||||
},
|
||||
{
|
||||
title: '## 🐛 Issues',
|
||||
labels: ['Issue'],
|
||||
rules: [
|
||||
@@ -627,8 +624,8 @@ it('Use Rules to get all open PRs in one Category and merged categorised.', asyn
|
||||
title: '## Open PRs only',
|
||||
rules: [
|
||||
{
|
||||
pattern: "open",
|
||||
on_property: "status"
|
||||
pattern: 'open',
|
||||
on_property: 'status'
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -637,11 +634,11 @@ it('Use Rules to get all open PRs in one Category and merged categorised.', asyn
|
||||
labels: ['Feature', 'Issue'],
|
||||
rules: [
|
||||
{
|
||||
pattern: "merged",
|
||||
on_property: "status"
|
||||
pattern: 'merged',
|
||||
on_property: 'status'
|
||||
}
|
||||
],
|
||||
exhaustive: true,
|
||||
exhaustive: true
|
||||
}
|
||||
]
|
||||
expect(buildChangelogTest(customConfig, prs)).toStrictEqual(
|
||||
@@ -649,7 +646,6 @@ it('Use Rules to get all open PRs in one Category and merged categorised.', asyn
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
function buildChangelogTest(config: Configuration, prs: PullRequestInfo[]): string {
|
||||
return buildChangelog(DefaultDiffInfo, prs, {
|
||||
owner: 'mikepenz',
|
||||
|
||||
+1511
-1382
File diff suppressed because it is too large
Load Diff
+1
-1
File diff suppressed because one or more lines are too long
+3
@@ -541,6 +541,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
github-pr-collector
|
||||
Apache 2.0
|
||||
|
||||
has-flag
|
||||
MIT
|
||||
MIT License
|
||||
|
||||
Generated
+28
-6
@@ -13,16 +13,11 @@
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@octokit/rest": "^19.0.11",
|
||||
"https-proxy-agent": "^7.0.0",
|
||||
"moment": "^2.29.4",
|
||||
"semver": "^7.5.1",
|
||||
"tunnel": "^0.0.6",
|
||||
"webpack": "^5.85.0"
|
||||
"github-pr-collector": "file:pr-collector"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.2.5",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@typescript-eslint/parser": "^5.59.8",
|
||||
"@vercel/ncc": "^0.36.1",
|
||||
"eslint": "^8.42.0",
|
||||
@@ -3768,6 +3763,10 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/github-pr-collector": {
|
||||
"resolved": "pr-collector",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
@@ -7063,6 +7062,29 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"pr-collector": {
|
||||
"name": "github-pr-collector",
|
||||
"version": "v1.0.0",
|
||||
"license": "Apache 2.0",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@octokit/rest": "^19.0.11",
|
||||
"https-proxy-agent": "^7.0.0",
|
||||
"moment": "^2.29.4",
|
||||
"semver": "^7.5.1",
|
||||
"webpack": "^5.85.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.2.5",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@vercel/ncc": "^0.36.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"prettier": "2.8.8",
|
||||
"typescript": "^5.1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-6
@@ -36,16 +36,11 @@
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@octokit/rest": "^19.0.11",
|
||||
"https-proxy-agent": "^7.0.0",
|
||||
"moment": "^2.29.4",
|
||||
"semver": "^7.5.1",
|
||||
"tunnel": "^0.0.6",
|
||||
"webpack": "^5.85.0"
|
||||
"github-pr-collector": "file:pr-collector"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.2.5",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@typescript-eslint/parser": "^5.59.8",
|
||||
"@vercel/ncc": "^0.36.1",
|
||||
"eslint": "^8.42.0",
|
||||
|
||||
Generated
+1322
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "github-pr-collector",
|
||||
"version": "v1.0.0",
|
||||
"description": "Library to fetch GitHub pull request between 2 tags/sha1 hashes.",
|
||||
"main": "lib/prCollector.js",
|
||||
"types": "lib/prCollector.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"format": "prettier --write **/*.ts",
|
||||
"format-check": "prettier --check **/*.ts",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"package": "ncc build --source-map --license licenses.txt",
|
||||
"test": "jest --passWithNoTests",
|
||||
"all": "npm run build && npm run format && npm run lint && npm run package && npm test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/mikepenz/release-changelog-builder.git"
|
||||
},
|
||||
"keywords": [
|
||||
"github",
|
||||
"actions",
|
||||
"changelog",
|
||||
"release-notes",
|
||||
"release",
|
||||
"notes",
|
||||
"change",
|
||||
"release-automation",
|
||||
"pull-requests",
|
||||
"issues",
|
||||
"labels"
|
||||
],
|
||||
"author": "Mike Penz",
|
||||
"license": "Apache 2.0",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@octokit/rest": "^19.0.11",
|
||||
"https-proxy-agent": "^7.0.0",
|
||||
"moment": "^2.29.4",
|
||||
"semver": "^7.5.1",
|
||||
"webpack": "^5.85.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.2.5",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@vercel/ncc": "^0.36.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"prettier": "2.8.8",
|
||||
"typescript": "^5.1.3"
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@ import * as core from '@actions/core'
|
||||
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
|
||||
import moment from 'moment'
|
||||
import {failOrError} from './utils'
|
||||
import {ReleaseNotesOptions} from './releaseNotesBuilder'
|
||||
import {PullRequestInfo} from './pullRequests'
|
||||
import {Options} from './prCollector'
|
||||
|
||||
export interface DiffInfo {
|
||||
changedFiles: number
|
||||
@@ -121,7 +121,7 @@ export class Commits {
|
||||
return commitsResult
|
||||
}
|
||||
|
||||
async getCommitHistory(options: ReleaseNotesOptions): Promise<DiffInfo> {
|
||||
async getCommitHistory(options: Options): Promise<DiffInfo> {
|
||||
const {owner, repo, fromTag, toTag, failOnError} = options
|
||||
core.info(`ℹ️ Comparing ${owner}/${repo} - '${fromTag.name}...${toTag.name}'`)
|
||||
|
||||
@@ -141,7 +141,7 @@ export class Commits {
|
||||
return diffInfo
|
||||
}
|
||||
|
||||
async generateCommitPRs(options: ReleaseNotesOptions): Promise<[DiffInfo, PullRequestInfo[]]> {
|
||||
async generateCommitPRs(options: Options): Promise<[DiffInfo, PullRequestInfo[]]> {
|
||||
const {owner, repo, configuration} = options
|
||||
|
||||
const diffInfo = await this.getCommitHistory(options)
|
||||
@@ -0,0 +1,55 @@
|
||||
export interface Configuration {
|
||||
max_tags_to_fetch: number
|
||||
max_pull_requests: number
|
||||
max_back_track_time_days: number
|
||||
exclude_merge_branches: string[]
|
||||
sort: Sort | string // "ASC" or "DESC"
|
||||
tag_resolver: TagResolver
|
||||
base_branches: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the properties of the PullRequestInfo useable in different configurations
|
||||
*/
|
||||
export type Property =
|
||||
| 'number'
|
||||
| 'title'
|
||||
| 'branch'
|
||||
| 'author'
|
||||
| 'labels'
|
||||
| 'milestone'
|
||||
| 'body'
|
||||
| 'assignees'
|
||||
| 'requestedReviewers'
|
||||
| 'approvedReviewers'
|
||||
| 'status'
|
||||
|
||||
export interface Rule extends Regex {
|
||||
on_property?: Property // retrieve the property to apply the rule on
|
||||
}
|
||||
|
||||
export interface Sort {
|
||||
order: 'ASC' | 'DESC' // the sorting order
|
||||
on_property: 'mergedAt' | 'title' // the property to sort on. (mergedAt falls back to createdAt)
|
||||
}
|
||||
|
||||
export interface TagResolver {
|
||||
method: string // semver, sort
|
||||
filter?: Regex // the regex to filter the tags, prior to sorting
|
||||
transformer?: Transformer // transforms the tag name using the regex, run after the filter
|
||||
}
|
||||
|
||||
export interface Regex {
|
||||
pattern: string // the regex pattern to match
|
||||
flags?: string // the regex flag to use for RegExp
|
||||
}
|
||||
|
||||
export interface Transformer extends Regex {
|
||||
target?: string // the target string to transform the source string using the regex to
|
||||
}
|
||||
|
||||
export interface Extractor extends Transformer {
|
||||
on_property?: Property[] | Property | undefined // retrieve the property to extract the value from
|
||||
method?: 'replace' | 'match' | undefined // the method to use to extract the value, `match` will not use the `target` property
|
||||
on_empty?: string | undefined // in case the regex results in an empty string, this value is gonna be used instead (only for label_extractor currently)
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
import * as core from '@actions/core'
|
||||
import {Configuration} from './configuration'
|
||||
import {Octokit} from '@octokit/rest'
|
||||
import {TagInfo, Tags} from './tags'
|
||||
import {failOrError} from './utils'
|
||||
import {HttpsProxyAgent} from 'https-proxy-agent'
|
||||
import {PullRequestInfo, PullRequests} from './pullRequests'
|
||||
import {Commits, DiffInfo} from './commits'
|
||||
|
||||
export interface Options {
|
||||
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 Data {
|
||||
diffInfo: DiffInfo
|
||||
mergedPullRequests: PullRequestInfo[]
|
||||
options: Options
|
||||
}
|
||||
|
||||
export class PullRequestCollector {
|
||||
constructor(
|
||||
private baseUrl: string | null,
|
||||
private token: string | null,
|
||||
private repositoryPath: string,
|
||||
private owner: string,
|
||||
private repo: string,
|
||||
private fromTag: string | null,
|
||||
private toTag: string | null,
|
||||
private includeOpen: boolean = false,
|
||||
private failOnError: boolean,
|
||||
private ignorePreReleases: boolean,
|
||||
private fetchReviewers: boolean = false,
|
||||
private fetchReleaseInformation: boolean = false,
|
||||
private fetchReviews: boolean = false,
|
||||
private commitMode: boolean = false,
|
||||
private configuration: Configuration
|
||||
) {}
|
||||
|
||||
async build(): Promise<Data | null> {
|
||||
// check proxy setup for GHES environments
|
||||
const proxy = process.env.https_proxy || process.env.HTTPS_PROXY
|
||||
const noProxy = process.env.no_proxy || process.env.NO_PROXY
|
||||
let noProxyArray: string[] = []
|
||||
if (noProxy) {
|
||||
noProxyArray = noProxy.split(',')
|
||||
}
|
||||
|
||||
// load octokit instance
|
||||
const octokit = new Octokit({
|
||||
auth: `token ${this.token || process.env.GITHUB_TOKEN}`,
|
||||
baseUrl: `${this.baseUrl || 'https://api.github.com'}`
|
||||
})
|
||||
|
||||
if (proxy) {
|
||||
const agent = new HttpsProxyAgent(proxy)
|
||||
octokit.hook.before('request', options => {
|
||||
if (noProxyArray.includes(options.request.hostname)) {
|
||||
return
|
||||
}
|
||||
options.request.agent = agent
|
||||
})
|
||||
}
|
||||
|
||||
// ensure proper from <-> to tag range
|
||||
core.startGroup(`🔖 Resolve tags`)
|
||||
const tagsApi = new Tags(octokit)
|
||||
const tagRange = await tagsApi.retrieveRange(
|
||||
this.repositoryPath,
|
||||
this.owner,
|
||||
this.repo,
|
||||
this.fromTag,
|
||||
this.toTag,
|
||||
this.ignorePreReleases,
|
||||
this.configuration.max_tags_to_fetch,
|
||||
this.configuration.tag_resolver
|
||||
)
|
||||
|
||||
let thisTag = tagRange.to
|
||||
if (!thisTag) {
|
||||
failOrError(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError)
|
||||
return null
|
||||
} else {
|
||||
core.setOutput('toTag', thisTag.name)
|
||||
core.debug(`Resolved 'toTag' as ${thisTag.name}`)
|
||||
}
|
||||
|
||||
let previousTag = tagRange.from
|
||||
if (previousTag == null) {
|
||||
failOrError(`💥 Unable to retrieve previous tag given ${this.toTag}`, this.failOnError)
|
||||
return null
|
||||
}
|
||||
core.setOutput('fromTag', previousTag.name)
|
||||
core.debug(`fromTag resolved via previousTag as: ${previousTag.name}`)
|
||||
|
||||
if (this.fetchReleaseInformation) {
|
||||
// load release information from the GitHub API
|
||||
core.info(`ℹ️ Fetching release information was enabled`)
|
||||
thisTag = await tagsApi.fillTagInformation(this.repositoryPath, this.owner, this.repo, thisTag)
|
||||
previousTag = await tagsApi.fillTagInformation(this.repositoryPath, this.owner, this.repo, previousTag)
|
||||
} else {
|
||||
core.debug(`ℹ️ Fetching release information was disabled`)
|
||||
}
|
||||
|
||||
core.endGroup()
|
||||
|
||||
const options = {
|
||||
owner: this.owner,
|
||||
repo: this.repo,
|
||||
fromTag: previousTag,
|
||||
toTag: thisTag,
|
||||
includeOpen: this.includeOpen,
|
||||
failOnError: this.failOnError,
|
||||
fetchReviewers: this.fetchReviewers,
|
||||
fetchReleaseInformation: this.fetchReleaseInformation,
|
||||
fetchReviews: this.fetchReviews,
|
||||
commitMode: this.commitMode,
|
||||
configuration: this.configuration
|
||||
}
|
||||
|
||||
return await pullData(octokit, options)
|
||||
}
|
||||
}
|
||||
|
||||
export async function pullData(octokit: Octokit, options: Options): Promise<Data | 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
|
||||
}
|
||||
core.endGroup()
|
||||
|
||||
return {
|
||||
diffInfo,
|
||||
mergedPullRequests,
|
||||
options
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import {Unpacked} from './utils'
|
||||
import moment from 'moment'
|
||||
import {Property, Sort} from './configuration'
|
||||
import {Commits, DiffInfo, filterCommits} from './commits'
|
||||
import {ReleaseNotesOptions} from './releaseNotesBuilder'
|
||||
import {Options} from './prCollector'
|
||||
|
||||
export interface PullRequestInfo {
|
||||
number: number
|
||||
@@ -162,7 +162,7 @@ export class PullRequests {
|
||||
pr.reviews = prReviews
|
||||
}
|
||||
|
||||
async getMergedPullRequests(options: ReleaseNotesOptions): Promise<[DiffInfo, PullRequestInfo[]]> {
|
||||
async getMergedPullRequests(options: Options): Promise<[DiffInfo, PullRequestInfo[]]> {
|
||||
const {owner, repo, includeOpen, fetchReviewers, fetchReviews, configuration} = options
|
||||
|
||||
const diffInfo = await this.commits.getCommitHistory(options)
|
||||
@@ -0,0 +1,49 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as fs from 'fs'
|
||||
|
||||
/**
|
||||
* Will automatically either report the message to the log, or mark the action as failed. Additionally defining the output failed, allowing it to be read in by other actions
|
||||
*/
|
||||
export function failOrError(message: string | Error, failOnError: boolean): void {
|
||||
// if we report any failure, consider the action to have failed, may not make the build fail
|
||||
core.setOutput('failed', true)
|
||||
if (failOnError) {
|
||||
core.setFailed(message)
|
||||
} else {
|
||||
core.error(message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given directory exists
|
||||
*/
|
||||
export function directoryExistsSync(inputPath: string, required?: boolean): boolean {
|
||||
if (!inputPath) {
|
||||
throw new Error("Arg 'path' must not be empty")
|
||||
}
|
||||
|
||||
let stats: fs.Stats
|
||||
try {
|
||||
stats = fs.statSync(inputPath)
|
||||
} catch (error: any /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
|
||||
if (error.code === 'ENOENT') {
|
||||
if (!required) {
|
||||
return false
|
||||
}
|
||||
|
||||
throw new Error(`Directory '${inputPath}' does not exist`)
|
||||
}
|
||||
|
||||
throw new Error(`Encountered an error when checking whether path '${inputPath}' exists: ${error.message}`)
|
||||
}
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
return true
|
||||
} else if (!required) {
|
||||
return false
|
||||
}
|
||||
|
||||
throw new Error(`Directory '${inputPath}' does not exist`)
|
||||
}
|
||||
|
||||
export type Unpacked<T> = T extends (infer U)[] ? U : T
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"outDir": "./lib", /* Redirect output structure to the directory. */
|
||||
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
"lib": [ "ES2021.String" ], /* Enable custom `ES2021.String` extension in typescript for `replaceAll` */
|
||||
"declaration": true
|
||||
},
|
||||
"exclude": ["node_modules", "**/*.test.ts", "lib"]
|
||||
}
|
||||
+2
-24
@@ -1,3 +1,5 @@
|
||||
import {Extractor, Regex, Rule, Sort, Transformer} from 'github-pr-collector/lib/configuration'
|
||||
|
||||
export interface Configuration {
|
||||
max_tags_to_fetch: number
|
||||
max_pull_requests: number
|
||||
@@ -45,30 +47,6 @@ export type Property =
|
||||
| 'approvedReviewers'
|
||||
| 'status'
|
||||
|
||||
export interface Rule extends Regex {
|
||||
on_property?: Property // retrieve the property to apply the rule on
|
||||
}
|
||||
|
||||
export interface Sort {
|
||||
order: 'ASC' | 'DESC' // the sorting order
|
||||
on_property: 'mergedAt' | 'title' // the property to sort on. (mergedAt falls back to createdAt)
|
||||
}
|
||||
|
||||
export interface Regex {
|
||||
pattern: string // the regex pattern to match
|
||||
flags?: string // the regex flag to use for RegExp
|
||||
}
|
||||
|
||||
export interface Transformer extends Regex {
|
||||
target?: string // the target string to transform the source string using the regex to
|
||||
}
|
||||
|
||||
export interface Extractor extends Transformer {
|
||||
on_property?: Property[] | Property | undefined // retrieve the property to extract the value from
|
||||
method?: 'replace' | 'match' | undefined // the method to use to extract the value, `match` will not use the `target` property
|
||||
on_empty?: string | undefined // in case the regex results in an empty string, this value is gonna be used instead (only for label_extractor currently)
|
||||
}
|
||||
|
||||
export interface TagResolver {
|
||||
method: string // semver, sort
|
||||
filter?: Regex // the regex to filter the tags, prior to sorting
|
||||
|
||||
+60
-131
@@ -1,12 +1,12 @@
|
||||
import * as core from '@actions/core'
|
||||
import {Configuration} from './configuration'
|
||||
import {Octokit} from '@octokit/rest'
|
||||
import {TagInfo, Tags} from './tags'
|
||||
import {checkExportedData, failOrError} from './utils'
|
||||
import {HttpsProxyAgent} from 'https-proxy-agent'
|
||||
import {PullRequestInfo, PullRequests} from './pullRequests'
|
||||
import {Commits, DiffInfo} from './commits'
|
||||
import {checkExportedData} from './utils'
|
||||
import {buildChangelog} from './transform'
|
||||
import {PullRequestCollector} from 'github-pr-collector'
|
||||
import {failOrError} from 'github-pr-collector/lib/utils'
|
||||
import {TagInfo} from 'github-pr-collector/lib/tags'
|
||||
import {DiffInfo} from 'github-pr-collector/lib/commits'
|
||||
import {PullRequestInfo} from 'github-pr-collector/lib/pullRequests'
|
||||
|
||||
export interface ReleaseNotesOptions {
|
||||
owner: string // the owner of the repository
|
||||
@@ -22,12 +22,11 @@ export interface ReleaseNotesOptions {
|
||||
configuration: Configuration // the configuration as defined in `configuration.ts`
|
||||
}
|
||||
|
||||
export interface ReleaseNotesData {
|
||||
export interface Data {
|
||||
diffInfo: DiffInfo
|
||||
mergedPullRequests: PullRequestInfo[]
|
||||
options: ReleaseNotesOptions
|
||||
}
|
||||
|
||||
export class ReleaseNotesBuilder {
|
||||
constructor(
|
||||
private baseUrl: string | null,
|
||||
@@ -69,77 +68,34 @@ export class ReleaseNotesBuilder {
|
||||
}
|
||||
core.endGroup()
|
||||
|
||||
// check proxy setup for GHES environments
|
||||
const proxy = process.env.https_proxy || process.env.HTTPS_PROXY
|
||||
const noProxy = process.env.no_proxy || process.env.NO_PROXY
|
||||
let noProxyArray: string[] = []
|
||||
if (noProxy) {
|
||||
noProxyArray = noProxy.split(',')
|
||||
}
|
||||
|
||||
// load octokit instance
|
||||
const octokit = new Octokit({
|
||||
auth: `token ${this.token || process.env.GITHUB_TOKEN}`,
|
||||
baseUrl: `${this.baseUrl || 'https://api.github.com'}`
|
||||
})
|
||||
|
||||
if (proxy) {
|
||||
const agent = new HttpsProxyAgent(proxy)
|
||||
octokit.hook.before('request', options => {
|
||||
if (noProxyArray.includes(options.request.hostname)) {
|
||||
return
|
||||
}
|
||||
options.request.agent = agent
|
||||
})
|
||||
}
|
||||
|
||||
// ensure proper from <-> to tag range
|
||||
core.startGroup(`🔖 Resolve tags`)
|
||||
const tagsApi = new Tags(octokit)
|
||||
const tagRange = await tagsApi.retrieveRange(
|
||||
const prData = await new PullRequestCollector(
|
||||
this.baseUrl,
|
||||
this.token,
|
||||
this.repositoryPath,
|
||||
this.owner,
|
||||
this.repo,
|
||||
this.fromTag,
|
||||
this.toTag,
|
||||
this.includeOpen,
|
||||
this.failOnError,
|
||||
this.ignorePreReleases,
|
||||
this.configuration.max_tags_to_fetch,
|
||||
this.configuration.tag_resolver
|
||||
)
|
||||
this.fetchReviewers,
|
||||
this.fetchReleaseInformation,
|
||||
this.fetchReviews,
|
||||
this.commitMode,
|
||||
this.configuration
|
||||
).build()
|
||||
|
||||
let thisTag = tagRange.to
|
||||
if (!thisTag) {
|
||||
failOrError(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError)
|
||||
return null
|
||||
} else {
|
||||
core.setOutput('toTag', thisTag.name)
|
||||
core.debug(`Resolved 'toTag' as ${thisTag.name}`)
|
||||
}
|
||||
|
||||
let previousTag = tagRange.from
|
||||
if (previousTag == null) {
|
||||
failOrError(`💥 Unable to retrieve previous tag given ${this.toTag}`, this.failOnError)
|
||||
if (prData == null) {
|
||||
return null
|
||||
}
|
||||
core.setOutput('fromTag', previousTag.name)
|
||||
core.debug(`fromTag resolved via previousTag as: ${previousTag.name}`)
|
||||
|
||||
if (this.fetchReleaseInformation) {
|
||||
// load release information from the GitHub API
|
||||
core.info(`ℹ️ Fetching release information was enabled`)
|
||||
thisTag = await tagsApi.fillTagInformation(this.repositoryPath, this.owner, this.repo, thisTag)
|
||||
previousTag = await tagsApi.fillTagInformation(this.repositoryPath, this.owner, this.repo, previousTag)
|
||||
} else {
|
||||
core.debug(`ℹ️ Fetching release information was disabled`)
|
||||
}
|
||||
|
||||
core.endGroup()
|
||||
|
||||
const options = {
|
||||
const resolvedOptions = prData.options
|
||||
const options: ReleaseNotesOptions = {
|
||||
owner: this.owner,
|
||||
repo: this.repo,
|
||||
fromTag: previousTag,
|
||||
toTag: thisTag,
|
||||
fromTag: resolvedOptions.fromTag,
|
||||
toTag: resolvedOptions.toTag,
|
||||
includeOpen: this.includeOpen,
|
||||
failOnError: this.failOnError,
|
||||
fetchReviewers: this.fetchReviewers,
|
||||
@@ -148,8 +104,44 @@ export class ReleaseNotesBuilder {
|
||||
commitMode: this.commitMode,
|
||||
configuration: this.configuration
|
||||
}
|
||||
const mergedPullRequests = prData.mergedPullRequests
|
||||
const diffInfo = prData.diffInfo
|
||||
|
||||
releaseNotesData = await pullData(octokit, options, this.exportCollected, this.exportOnly)
|
||||
// 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 (this.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 (this.exportOnly) {
|
||||
core.endGroup()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
releaseNotesData = {
|
||||
mergedPullRequests,
|
||||
diffInfo,
|
||||
options
|
||||
}
|
||||
} else {
|
||||
core.info(`ℹ️ Retrieved previously exported collected data`)
|
||||
|
||||
@@ -196,66 +188,3 @@ export class ReleaseNotesBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -1,10 +1,11 @@
|
||||
import * as core from '@actions/core'
|
||||
import {Category, Configuration, Placeholder, Property, Transformer} from './configuration'
|
||||
import {CommentInfo, EMPTY_COMMENT_INFO, PullRequestInfo, retrieveProperty, sortPullRequests} from './pullRequests'
|
||||
import {ReleaseNotesOptions} from './releaseNotesBuilder'
|
||||
import {DiffInfo} from './commits'
|
||||
import {Category, Configuration, Placeholder, Property} from './configuration'
|
||||
import {createOrSet, haveCommonElementsArr, haveEveryElementsArr} from './utils'
|
||||
import {matchesRules, RegexTransformer, validateTransformer} from './regexUtils'
|
||||
import {CommentInfo, EMPTY_COMMENT_INFO, PullRequestInfo, retrieveProperty, sortPullRequests} from 'github-pr-collector/lib/pullRequests'
|
||||
import {DiffInfo} from 'github-pr-collector/lib/commits'
|
||||
import {RegexTransformer, matchesRules, validateTransformer} from 'github-pr-collector/lib/regexUtils'
|
||||
import {Transformer} from 'github-pr-collector/lib/configuration'
|
||||
import {ReleaseNotesOptions} from './releaseNotesBuilder'
|
||||
|
||||
const EMPTY_MAP = new Map<string, string>()
|
||||
|
||||
|
||||
+4
-51
@@ -2,10 +2,10 @@ import * as core from '@actions/core'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import {Configuration, DefaultConfiguration} from './configuration'
|
||||
import {ReleaseNotesData, ReleaseNotesOptions} from './releaseNotesBuilder'
|
||||
import {DiffInfo} from './commits'
|
||||
import {PullRequestInfo} from './pullRequests'
|
||||
import moment from 'moment'
|
||||
import {DiffInfo} from 'github-pr-collector/lib/commits'
|
||||
import {PullRequestInfo} from 'github-pr-collector/lib/pullRequests'
|
||||
import {Data, ReleaseNotesOptions} from './releaseNotesBuilder'
|
||||
/**
|
||||
* Resolves the repository path, relatively to the GITHUB_WORKSPACE
|
||||
*/
|
||||
@@ -23,24 +23,11 @@ export function retrieveRepositoryPath(providedPath: string): string {
|
||||
return repositoryPath
|
||||
}
|
||||
|
||||
/**
|
||||
* Will automatically either report the message to the log, or mark the action as failed. Additionally defining the output failed, allowing it to be read in by other actions
|
||||
*/
|
||||
export function failOrError(message: string | Error, failOnError: boolean): void {
|
||||
// if we report any failure, consider the action to have failed, may not make the build fail
|
||||
core.setOutput('failed', true)
|
||||
if (failOnError) {
|
||||
core.setFailed(message)
|
||||
} else {
|
||||
core.error(message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the exported information from a previous run of the `release-changelog-builder-action`.
|
||||
* If available, return a [ReleaseNotesData].
|
||||
*/
|
||||
export function checkExportedData(): ReleaseNotesData | null {
|
||||
export function checkExportedData(): Data | null {
|
||||
const rawDiffInfo = process.env[`RCBA_EXPORT_diffInfo`]
|
||||
const rawMergedPullRequests = process.env[`RCBA_EXPORT_mergedPullRequests`]
|
||||
const rawOptions = process.env[`RCBA_EXPORT_options`]
|
||||
@@ -153,38 +140,6 @@ export function mergeConfiguration(jc?: Configuration, fc?: Configuration): Conf
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given directory exists
|
||||
*/
|
||||
export function directoryExistsSync(inputPath: string, required?: boolean): boolean {
|
||||
if (!inputPath) {
|
||||
throw new Error("Arg 'path' must not be empty")
|
||||
}
|
||||
|
||||
let stats: fs.Stats
|
||||
try {
|
||||
stats = fs.statSync(inputPath)
|
||||
} catch (error: any /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
|
||||
if (error.code === 'ENOENT') {
|
||||
if (!required) {
|
||||
return false
|
||||
}
|
||||
|
||||
throw new Error(`Directory '${inputPath}' does not exist`)
|
||||
}
|
||||
|
||||
throw new Error(`Encountered an error when checking whether path '${inputPath}' exists: ${error.message}`)
|
||||
}
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
return true
|
||||
} else if (!required) {
|
||||
return false
|
||||
}
|
||||
|
||||
throw new Error(`Directory '${inputPath}' does not exist`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the changelog to the given the file
|
||||
*/
|
||||
@@ -200,8 +155,6 @@ export function writeOutput(githubWorkspacePath: string, outputFile: string, cha
|
||||
}
|
||||
}
|
||||
|
||||
export type Unpacked<T> = T extends (infer U)[] ? U : T
|
||||
|
||||
export function createOrSet<T>(map: Map<string, T[]>, key: string, value: T): void {
|
||||
const entry = map.get(key)
|
||||
if (!entry) {
|
||||
|
||||
+1
-1
@@ -9,5 +9,5 @@
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
"lib": [ "ES2021.String" ] /* Enable custom `ES2021.String` extension in typescript for `replaceAll` */
|
||||
},
|
||||
"exclude": ["node_modules", "**/*.test.ts"]
|
||||
"exclude": ["node_modules", "**/*.test.ts", "pr-collector"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user