Merge branch 'pr/dreamncn/1273' into develop

This commit is contained in:
Mike Penz
2023-11-05 10:30:28 +00:00
committed by GitHub
38 changed files with 9464 additions and 792 deletions
+1 -1
View File
@@ -99,4 +99,4 @@ __tests__/runner/*
lib/**/*
lib
pr-collector/dist
src/pr-collector/dist
@@ -0,0 +1,793 @@
import {mergeConfiguration, resolveConfiguration} from '../../src/utils'
import {ReleaseNotesBuilder} from '../../src/releaseNotesBuilder'
import {GiteaRepository} from '../../src/repositories/GiteaRepository'
jest.setTimeout(180000)
/**
* Before starting testing, you should manually clone the repository
* cd /tmp && git clone https://gitea.com/mikepenz/sip
*
* (Forked from: https://gitea.com/jolheiser/sip)
*/
const token = process.env.GITEA_TOKEN || ''
const workingDirectory = '/tmp/sip/'
const owner = 'jolheiser'
const repo = 'sip'
const configurationFile = 'configs/configuration_gitea.json'
it('[Gitea] Verify reviewers who approved are fetched and also release information', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_approvers.json'))
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
giteaRepository, // token
workingDirectory, // repoPath
owner, // user
repo, // repo
'v0.5.0', // fromTag
'master', // toTag
true, // includeOpen
false, // failOnError
false, // ignorePrePrelease
false, // enable to fetch via commits
true, // enable to fetch reviewers
true, // enable to fetch tag release information
false, // enable to fetch reviews
false, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration // configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(
`## 📦 Uncategorized
- Add attachment removal and change message -- (#36) [merged] ---
- Change to vanity URL -- (#37) [merged] ---
4`
)
})
it('[Gitea] Should match generated changelog (unspecified fromTag)', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', configurationFile))
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
giteaRepository,
workingDirectory,
owner,
repo,
null,
'v0.1.1',
false,
false,
false,
true, // enable to fetch via commits
false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // enable to fetch reviews
false, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(`## 🧪 Upgrade
- Clean up and polish
- PR: #1
`)
})
//
it('[Gitea] Should match generated changelog (unspecified tags)', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', configurationFile))
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
giteaRepository,
workingDirectory,
owner,
repo,
null,
null,
false,
false,
false,
false, // enable to fetch via commits
false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // enable to fetch reviews
false, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(`## 🚀 Features
- Add release attachments
- PR: #26
`)
})
it('[Gitea] Should use empty placeholder', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', configurationFile))
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
giteaRepository,
workingDirectory,
owner,
repo,
'v0.1.1',
'v0.3.0',
false,
false,
false,
true, // enable to fetch via commits
false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // enable to fetch reviews
false, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(`## 🚀 Features
- Add Drone and releases
- PR: #2
- Add search filters
- PR: #8
- Add qualifier module
- PR: #10
- Add create repo command
- PR: #13
- Add release support and CSV output
- PR: #16
## 🐛 Fixes
- Fix PR head nil panic
- PR: #7
- Fix Drone release
- PR: #14
`)
})
it('[Gitea] Should fill empty placeholders', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_empty_all_placeholders.json'))
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
giteaRepository,
workingDirectory,
owner,
repo,
'v0.1.0',
'v0.4.0',
false,
false,
false,
true, // enable to fetch via commits
false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // enable to fetch reviews
false, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(
`## 🚀 Features
- Add create repo command
- PR: #13
- Add release support and CSV output
- PR: #16
- Add open functionality
- PR: #21
## 📦 Uncategorized
- Clean up and polish
- PR: #1
- Add Drone and releases
- PR: #2
- Update Beaver and fix bugs
- PR: #6
- Fix PR head nil panic
- PR: #7
- Add search filters
- PR: #8
- Changelog 0.2.0
- PR: #9
- Add qualifier module
- PR: #10
- Fix Drone release
- PR: #14
- Imp formatting
- PR: #17
- Update Gitea SDK and other modules
- PR: #19
- Update modules
- PR: #20
- Add changelog for 0.3.0 and 0.4.0
- PR: #22
- Clean up and polish
- PR: #1
- Add Drone and releases
- PR: #2
- Update Beaver and fix bugs
- PR: #6
- Fix PR head nil panic
- PR: #7
- Add search filters
- PR: #8
- Changelog 0.2.0
- PR: #9
- Add qualifier module
- PR: #10
- Fix Drone release
- PR: #14
- Imp formatting
- PR: #17
- Update Gitea SDK and other modules
- PR: #19
- Update modules
- PR: #20
- Add changelog for 0.3.0 and 0.4.0
- PR: #22
jolheiser
sip
v0.1.0
v0.4.0
https://gitea.com/jolheiser/sip/compare/v0.1.0...v0.4.0
3
12
0
36
1322
274
0
16`
)
})
it('[Gitea] Should fill `template` placeholders', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_empty_all_placeholders.json'))
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
giteaRepository,
workingDirectory,
owner,
repo,
'v0.1.0',
'v0.4.0',
false,
false,
false,
true, // enable to fetch via commits
false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // enable to fetch reviews
false, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(
`## 🚀 Features
- Add create repo command
- PR: #13
- Add release support and CSV output
- PR: #16
- Add open functionality
- PR: #21
## 📦 Uncategorized
- Clean up and polish
- PR: #1
- Add Drone and releases
- PR: #2
- Update Beaver and fix bugs
- PR: #6
- Fix PR head nil panic
- PR: #7
- Add search filters
- PR: #8
- Changelog 0.2.0
- PR: #9
- Add qualifier module
- PR: #10
- Fix Drone release
- PR: #14
- Imp formatting
- PR: #17
- Update Gitea SDK and other modules
- PR: #19
- Update modules
- PR: #20
- Add changelog for 0.3.0 and 0.4.0
- PR: #22
- Clean up and polish
- PR: #1
- Add Drone and releases
- PR: #2
- Update Beaver and fix bugs
- PR: #6
- Fix PR head nil panic
- PR: #7
- Add search filters
- PR: #8
- Changelog 0.2.0
- PR: #9
- Add qualifier module
- PR: #10
- Fix Drone release
- PR: #14
- Imp formatting
- PR: #17
- Update Gitea SDK and other modules
- PR: #19
- Update modules
- PR: #20
- Add changelog for 0.3.0 and 0.4.0
- PR: #22
jolheiser
sip
v0.1.0
v0.4.0
https://gitea.com/jolheiser/sip/compare/v0.1.0...v0.4.0
3
12
0
36
1322
274
0
16`
)
})
it('[Gitea] Should fill `template` placeholders, ignore', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_empty_all_placeholders.json'))
configuration.categories.pop() // drop `uncategorized` category
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
giteaRepository,
workingDirectory,
owner,
repo,
'v0.3.0',
'v0.5.0',
false,
false,
false,
false, // enable to fetch via commits
false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // enable to fetch reviews
false, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(
`## 🚀 Features
- Add open functionality
- PR: #21
- Update modules
- PR: #20
- Add changelog for 0.3.0 and 0.4.0
- PR: #22
- Update Gitea SDK
- PR: #23
- Update repo info
- PR: #24
- Add release attachments
- PR: #26
- Refactor
- PR: #29
jolheiser
sip
v0.3.0
v0.5.0
https://gitea.com/jolheiser/sip/compare/v0.3.0...v0.5.0
1
6
0
41
748
314
0
8`
)
})
it('[Gitea] Uncategorized category', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_uncategorized_category.json'))
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
giteaRepository,
workingDirectory,
owner,
repo,
'v0.3.0',
'v0.5.0',
false,
false,
false,
false, // enable to fetch via commits
false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // enable to fetch reviews
false, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(
`## 🚀 Features
- Add open functionality
- PR: #21
## 📦 Uncategorized
- Update modules
- PR: #20
- Add changelog for 0.3.0 and 0.4.0
- PR: #22
- Update Gitea SDK
- PR: #23
- Update repo info
- PR: #24
- Add release attachments
- PR: #26
- Refactor
- PR: #29
Uncategorized:
- Update modules
- PR: #20
- Add changelog for 0.3.0 and 0.4.0
- PR: #22
- Update Gitea SDK
- PR: #23
- Update repo info
- PR: #24
- Add release attachments
- PR: #26
- Refactor
- PR: #29
Ignored:
6
0`
)
})
it('[Gitea] Verify commit based changelog', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_commits.json'))
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
giteaRepository,
workingDirectory,
owner,
repo,
'v0.3.0',
'v0.5.0',
false,
false,
false,
true, // enable to fetch via commits
false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // enable to fetch reviews
true, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(
`## 📦 Uncategorized
- Update modules (#20)
- Add open functionality (#21)
- Add changelog for 0.3.0 and 0.4.0 (#22)
- Update Gitea SDK (#23)
- Update repo info (#24)
- Add release attachments (#26)
- Refactor (#29)
- Changelog 0.5.0 (#30)
Uncategorized:
- Update modules (#20)
- Add open functionality (#21)
- Add changelog for 0.3.0 and 0.4.0 (#22)
- Update Gitea SDK (#23)
- Update repo info (#24)
- Add release attachments (#26)
- Refactor (#29)
- Changelog 0.5.0 (#30)
Ignored:
8
0`
)
})
it('[Gitea] Verify commit based changelog', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', configurationFile))
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
giteaRepository,
workingDirectory,
owner,
repo,
'3e49adf6047960a03f53346bbececb3ce7e0809b',
'894a641ef86c444dccfa55eca457186b5e10da95',
false,
false,
false,
false, // enable to fetch via commits
false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // enable to fetch reviews
true, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(
`## 🚀 Features
- Add release attachments (#26)
- PR: #0
`
)
})
// no open prs
it('[Gitea] Verify default inclusion of open PRs', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_including_open.json'))
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
giteaRepository, // token
workingDirectory, // repoPath
owner, // user
repo, // repo
'v0.5.0', // fromTag
'master', // toTag
true, // includeOpen
false, // failOnError
false, // ignorePrePrelease
false, // enable to fetch via commits
false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // enable to fetch reviews
false, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration // configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(`
Uncategorized
- Add attachment removal and change message (#36) merged
- Change to vanity URL (#37) merged
Open
`)
})
it('[Gitea] Verify custom categorisation of open PRs', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_excluding_open.json'))
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
giteaRepository, // token
workingDirectory, // repoPath
owner, // user
repo, // repo
'v0.5.0', // fromTag
'master', // toTag
true, // includeOpen
false, // failOnError
false, // ignorePrePrelease
false, // enable to fetch via commits
false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // enable to fetch reviews
false, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration // configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(``)
})
it('[Gitea] Fetch release information', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_approvers.json'))
configuration.template = '#{{FROM_TAG}}-#{{FROM_TAG_DATE}}\n#{{TO_TAG}}-#{{TO_TAG_DATE}}\n#{{DAYS_SINCE}}'
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
giteaRepository, // token
workingDirectory, // repoPath
owner, // user
repo, // repo
'v0.5.0', // fromTag
'master', // toTag
true, // includeOpen
false, // failOnError
false, // ignorePrePrelease
false, // enable to fetch via commits
false, // enable to fetch reviewers
true, // enable to fetch tag release information
false, // enable to fetch reviews
false, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration // configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(`v0.5.0-2020-09-17T16:34:40.000Z
master-2020-09-21T19:30:21.000Z
4`)
})
it('[Gitea] Fetch release information for non existing tag / release', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_approvers.json'))
configuration.template = '#{{FROM_TAG}}-#{{FROM_TAG_DATE}}\n#{{TO_TAG}}-#{{TO_TAG_DATE}}\n#{{DAYS_SINCE}}'
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
giteaRepository, // token
workingDirectory, // repoPath
owner, // user
repo, // repo
'v0.5.0', // fromTag
'master', // toTag
true, // includeOpen
false, // failOnError
false, // ignorePrePrelease
false, // enable to fetch via commits
false, // enable to fetch reviewers
true, // enable to fetch tag release information
false, // enable to fetch reviews
false, // enable commitMode
false, // enable exportCache
false, // enable exportOnly
null, // path to the cache
configuration // configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(`v0.5.0-2020-09-17T16:34:40.000Z
master-2020-09-21T19:30:21.000Z
4`)
})
@@ -0,0 +1,349 @@
import {checkExportedData, mergeConfiguration, resolveConfiguration} from '../../src/utils'
import {buildChangelog} from '../../src/transform'
import {pullData} from '../../src/pr-collector/prCollector'
import {GiteaRepository} from '../../src/repositories/GiteaRepository'
jest.setTimeout(180000)
// load octokit instance
const enablePullData = false
/**
* if false -> use cache for data
* Use the below snippet to export the cache:
*
* writeCacheData({
* mergedPullRequests: data.mergedPullRequests,
* diffInfo: data.diffInfo,
* options
* }, 'caches/gitea_rcba_0.1.0-master_cache.json')
*/
/**
* Before starting testing, you should manually clone the repository
* cd /tmp && git clone https://gitea.com/mikepenz/sip
*
* (Forked from: https://gitea.com/jolheiser/sip)
*/
const token = process.env.GITEA_TOKEN || ''
const workingDirectory = '/tmp/sip/'
const owner = 'jolheiser'
const repo = 'sip'
const giteaRepository = new GiteaRepository(token, undefined, workingDirectory)
const configurationFile = 'configs/configuration_gitea.json'
it('[Gitea] Should have changelog (tags)', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', configurationFile))
const options = {
owner: owner,
repo: repo,
fromTag: {name: 'v0.5.0'},
toTag: {name: 'master'},
includeOpen: false,
failOnError: false,
fetchViaCommits: true,
fetchReviewers: false,
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration,
repositoryUtils: giteaRepository
}
let data: any
if (enablePullData) {
data = await pullData(giteaRepository, options)
} else {
data = checkExportedData(false, 'caches/gitea_rcba_0.5.0-master_cache.json')
}
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, options)
console.log(changeLog)
expect(changeLog).toStrictEqual(`## 🚀 Features
- Add attachment removal and change message
- PR: #36
## 🐛 Fixes
- Fix drone-gitea-main
- PR: #38
`)
})
it('[Gitea] Should match generated changelog (tags)', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', configurationFile))
const options = {
owner: owner,
repo: repo,
fromTag: {name: 'v0.5.0'},
toTag: {name: 'master'},
includeOpen: false,
failOnError: false,
fetchViaCommits: true,
fetchReviewers: false,
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration,
repositoryUtils: giteaRepository
}
let data: any
if (enablePullData) {
data = await pullData(giteaRepository, options)
} else {
data = checkExportedData(false, 'caches/gitea_rcba_0.5.0-master_cache.json')
}
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, options)
console.log(changeLog)
expect(changeLog).toStrictEqual(`## 🚀 Features
- Add attachment removal and change message
- PR: #36
## 🐛 Fixes
- Fix drone-gitea-main
- PR: #38
`)
})
it('[Gitea] Should match generated changelog (refs)', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_all_placeholders.json'))
const options = {
owner: owner,
repo: repo,
fromTag: {name: '3e49adf6047960a03f53346bbececb3ce7e0809b'},
toTag: {name: '894a641ef86c444dccfa55eca457186b5e10da95'},
includeOpen: false,
failOnError: false,
fetchViaCommits: true,
fetchReviewers: false,
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration,
repositoryUtils: giteaRepository
}
let data: any
if (enablePullData) {
data = await pullData(giteaRepository, options)
} else {
data = checkExportedData(false, 'caches/gitea_rcba_3e49adf-894a64_cache.json')
}
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, options)
console.log(changeLog)
expect(changeLog).toStrictEqual(`## 📦 Uncategorized
Add release attachments
26
https://gitea.com/jolheiser/sip/pulls/26
2020-09-16T18:07:32.000Z
jolheiser
enhancement
0.5.0
Resolves #25
Refactor
29
https://gitea.com/jolheiser/sip/pulls/29
2020-09-17T16:25:11.000Z
jolheiser
enhancement
0.5.0
Fixes #27
Fixes #28
This PR refactors and cleans up packages.
It also scans CLI flags into variables for fewer footguns.
`)
})
it('[Gitea] Should match generated changelog and replace all occurrences (refs)', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_replace_all_placeholders.json'))
const options = {
owner: owner,
repo: repo,
fromTag: {name: '3e49adf6047960a03f53346bbececb3ce7e0809b'},
toTag: {name: '894a641ef86c444dccfa55eca457186b5e10da95'},
includeOpen: false,
failOnError: false,
fetchViaCommits: true,
fetchReviewers: false,
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration,
repositoryUtils: giteaRepository
}
let data: any
if (enablePullData) {
data = await pullData(giteaRepository, options)
} else {
data = checkExportedData(false, 'caches/gitea_rcba_3e49adf-894a64_cache.json')
}
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, options)
console.log(changeLog)
expect(changeLog).toStrictEqual(`## 📦 Uncategorized
Add release attachments
Add release attachments
26
https://gitea.com/jolheiser/sip/pulls/26
2020-09-16T18:07:32.000Z
jolheiser
jolheiser
enhancement
0.5.0
Resolves #25
Refactor
Refactor
29
https://gitea.com/jolheiser/sip/pulls/29
2020-09-17T16:25:11.000Z
jolheiser
jolheiser
enhancement
0.5.0
Fixes #27
Fixes #28
This PR refactors and cleans up packages.
It also scans CLI flags into variables for fewer footguns.
`)
})
it('[Gitea] Should match ordered ASC', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', configurationFile))
configuration.categories.pop() // drop `uncategorized` category
const options = {
owner: owner,
repo: repo,
fromTag: {name: 'v0.1.0'},
toTag: {name: 'master'},
includeOpen: false,
failOnError: false,
fetchViaCommits: false,
fetchReviewers: false,
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration,
repositoryUtils: giteaRepository
}
let data: any
if (enablePullData) {
data = await pullData(giteaRepository, options)
} else {
data = checkExportedData(false, 'caches/gitea_rcba_0.1.0-master_cache.json')
}
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, options)
console.log(changeLog)
expect(changeLog).toStrictEqual(`## 🚀 Features
- Add Drone and releases
- PR: #2
- Add search filters
- PR: #8
- Add qualifier module
- PR: #10
- Add create repo command
- PR: #13
- Add release support and CSV output
- PR: #16
- Add open functionality
- PR: #21
- Add changelog for 0.3.0 and 0.4.0
- PR: #22
- Add release attachments
- PR: #26
- Add attachment removal and change message
- PR: #36
## 🐛 Fixes
- Fix PR head nil panic
- PR: #7
- Fix Drone release
- PR: #14
`)
})
it('[Gitea] Should match ordered DESC', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_gitea_desc.json'))
configuration.categories.pop() // drop `uncategorized` category
const options = {
owner: owner,
repo: repo,
fromTag: {name: 'v0.1.0'},
toTag: {name: 'master'},
includeOpen: false,
failOnError: false,
fetchViaCommits: false,
fetchReviewers: false,
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration,
repositoryUtils: giteaRepository
}
let data: any
if (enablePullData) {
data = await pullData(giteaRepository, options)
} else {
data = checkExportedData(false, 'caches/gitea_rcba_0.1.0-master_cache.json')
}
const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, options)
console.log(changeLog)
expect(changeLog).toStrictEqual(`## 🚀 Features
- Add attachment removal and change message
- PR: #36
- Add release attachments
- PR: #26
- Add changelog for 0.3.0 and 0.4.0
- PR: #22
- Add open functionality
- PR: #21
- Add release support and CSV output
- PR: #16
- Add create repo command
- PR: #13
- Add qualifier module
- PR: #10
- Add search filters
- PR: #8
- Add Drone and releases
- PR: #2
## 🐛 Fixes
- Fix Drone release
- PR: #14
- Fix PR head nil panic
- PR: #7
`)
})
/*
* I delete these test cases about gitea
* Should match ordered by title ASC
* Should match ordered by title DESC
* Should ignore PRs not merged into develop branch
*/
+8 -4
View File
@@ -6,17 +6,19 @@ import * as fs from 'fs'
jest.setTimeout(180000)
test('missing values should result in failure', () => {
expect.assertions(1)
process.env['GITHUB_WORKSPACE'] = '.'
process.env['INPUT_CONFIGURATION'] = 'configuration.json'
process.env['INPUT_OWNER'] = undefined
process.env['INPUT_CONFIGURATION'] = 'configs/configuration.json'
const ip = path.join(__dirname, '..', 'lib', 'main.js')
const options: cp.ExecSyncOptions = {
env: process.env
}
try {
cp.execSync(`node ${ip}`, options).toString()
fail('Should not succeed, because values miss')
} catch (error) {
console.log(`correctly failed due to: ${error}`)
} catch (error: any) {
expect(true).toBe(true)
}
})
@@ -27,6 +29,7 @@ test('complete input should succeed', () => {
process.env['INPUT_REPO'] = 'release-changelog-builder-action'
process.env['INPUT_FROMTAG'] = 'v0.3.0'
process.env['INPUT_TOTAG'] = 'v0.5.0'
process.env['INPUT_CACHE'] = 'caches/rcba_0.3.0-0.5.0_cache.json'
const ip = path.join(__dirname, '..', 'lib', 'main.js')
const options: cp.ExecSyncOptions = {
@@ -45,6 +48,7 @@ test('should write result to file', () => {
process.env['INPUT_FROMTAG'] = 'v0.3.0'
process.env['INPUT_TOTAG'] = 'v0.5.0'
process.env['INPUT_OUTPUTFILE'] = 'test.md'
process.env['INPUT_CACHE'] = 'caches/rcba_0.3.0-0.5.0_cache.json'
const ip = path.join(__dirname, '..', 'lib', 'main.js')
const options: cp.ExecSyncOptions = {
+31 -28
View File
@@ -1,13 +1,16 @@
import {mergeConfiguration, resolveConfiguration} from '../src/utils'
import {ReleaseNotesBuilder} from '../src/releaseNotesBuilder'
import {GithubRepository} from '../src/repositories/GithubRepository'
jest.setTimeout(180000)
it('Should match generated changelog (unspecified fromTag)', async () => {
const token = process.env.GITHUB_TOKEN || ''
const githubRepository = new GithubRepository(token, undefined, '.')
it('[Github] Should match generated changelog (unspecified fromTag)', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs/configuration.json'))
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
null,
githubRepository,
'.',
'mikepenz',
'release-changelog-builder-action',
@@ -37,11 +40,11 @@ it('Should match generated changelog (unspecified fromTag)', async () => {
`)
})
it('Should match generated changelog (unspecified tags)', async () => {
it('[Github] Should match generated changelog (unspecified tags)', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs/configuration.json'))
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
null,
githubRepository,
'.',
'mikepenz',
'action-junit-report-legacy',
@@ -66,11 +69,11 @@ it('Should match generated changelog (unspecified tags)', async () => {
expect(changeLog).toStrictEqual(`## 🐛 Fixes\n\n- Stacktrace Data can be an array\n - PR: #39\n\n`)
})
it('Should use empty placeholder', async () => {
it('[Github] Should use empty placeholder', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs/configuration.json'))
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
null,
githubRepository,
'.',
'mikepenz',
'release-changelog-builder-action',
@@ -95,11 +98,11 @@ it('Should use empty placeholder', async () => {
expect(changeLog).toStrictEqual(`- no changes`)
})
it('Should fill empty placeholders', async () => {
it('[Github] Should fill empty placeholders', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_empty_all_placeholders.json'))
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
null,
githubRepository,
'.',
'mikepenz',
'release-changelog-builder-action',
@@ -126,11 +129,11 @@ it('Should fill empty placeholders', async () => {
)
})
it('Should fill `template` placeholders', async () => {
it('[Github] Should fill `template` placeholders', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_empty_all_placeholders.json'))
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
null,
githubRepository,
'.',
'mikepenz',
'release-changelog-builder-action',
@@ -157,12 +160,12 @@ it('Should fill `template` placeholders', async () => {
)
})
it('Should fill `template` placeholders, ignore', async () => {
it('[Github] Should fill `template` placeholders, ignore', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_empty_all_placeholders.json'))
configuration.categories.pop() // drop `uncategorized` category
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
null,
githubRepository,
'.',
'mikepenz',
'release-changelog-builder-action',
@@ -189,11 +192,11 @@ it('Should fill `template` placeholders, ignore', async () => {
)
})
it('Uncategorized category', async () => {
it('[Github] Uncategorized category', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_uncategorized_category.json'))
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
null,
githubRepository,
'.',
'mikepenz',
'release-changelog-builder-action',
@@ -220,11 +223,11 @@ it('Uncategorized category', async () => {
)
})
it('Verify commit based changelog', async () => {
it('[Github] Verify commit based changelog', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_commits.json'))
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
null,
githubRepository,
'.',
'mikepenz',
'release-changelog-builder-action',
@@ -251,11 +254,11 @@ it('Verify commit based changelog', async () => {
)
})
it('Verify commit based changelog, with emoji categorisation', async () => {
it('[Github] Verify commit based changelog, with emoji categorisation', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_commits_emoji.json'))
const releaseNotesBuilder = new ReleaseNotesBuilder(
null,
null,
githubRepository,
'.',
'theapache64',
'stackzy',
@@ -282,11 +285,11 @@ it('Verify commit based changelog, with emoji categorisation', async () => {
)
})
it('Verify default inclusion of open PRs', async () => {
it('[Github] Verify default inclusion of open PRs', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_including_open.json'))
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
null, // token
githubRepository, // token
'.', // repoPath
'mikepenz', // user
'release-changelog-builder-action-playground', // repo
@@ -313,11 +316,11 @@ it('Verify default inclusion of open PRs', async () => {
)
})
it('Verify custom categorisation of open PRs', async () => {
it('[Github] Verify custom categorisation of open PRs', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_excluding_open.json'))
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
null, // token
githubRepository, // token
'.', // repoPath
'mikepenz', // user
'release-changelog-builder-action-playground', // repo
@@ -344,11 +347,11 @@ it('Verify custom categorisation of open PRs', async () => {
)
})
it('Verify reviewers who approved are fetched and also release information', async () => {
it('[Github] Verify reviewers who approved are fetched and also release information', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_approvers.json'))
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
null, // token
githubRepository, // token
'.', // repoPath
'mikepenz', // user
'release-changelog-builder-action-playground', // repo
@@ -375,12 +378,12 @@ it('Verify reviewers who approved are fetched and also release information', asy
)
})
it('Fetch release information', async () => {
it('[Github] Fetch release information', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_approvers.json'))
configuration.template = '#{{FROM_TAG}}-#{{FROM_TAG_DATE}}\n#{{TO_TAG}}-#{{TO_TAG_DATE}}\n#{{DAYS_SINCE}}'
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
null, // token
githubRepository, // token
'.', // repoPath
'mikepenz', // user
'release-changelog-builder-action-playground', // repo
@@ -405,12 +408,12 @@ it('Fetch release information', async () => {
expect(changeLog).toStrictEqual(`2.0.0-2022-04-08T07:52:40.000Z\n3.0.0-a01-2022-07-26T14:28:36.000Z\n109`)
})
it('Fetch release information for non existing tag / release', async () => {
it('[Github] Fetch release information for non existing tag / release', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs_test/configuration_approvers.json'))
configuration.template = '#{{FROM_TAG}}-#{{FROM_TAG_DATE}}\n#{{TO_TAG}}-#{{TO_TAG_DATE}}\n#{{DAYS_SINCE}}'
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
null, // token
githubRepository, // token
'.', // repoPath
'mikepenz', // user
'release-changelog-builder-action-playground', // repo
+33 -25
View File
@@ -1,17 +1,15 @@
import {checkExportedData, mergeConfiguration, resolveConfiguration} from '../src/utils'
import {Octokit} from '@octokit/rest'
import {buildChangelog} from '../src/transform'
import {pullData} from '../src/pr-collector/prCollector'
import {Data} from '../src/releaseNotesBuilder'
import {GithubRepository} from '../src/repositories/GithubRepository'
jest.setTimeout(180000)
// load octokit instance
const enablePullData = false // if false -> use cache for data
const octokit = new Octokit({
auth: `token ${process.env.GITHUB_TOKEN}`
})
const token = process.env.GITHUB_TOKEN || ''
const githubRepository = new GithubRepository(token, undefined, '.')
it('Should have empty changelog (tags)', async () => {
const configuration = mergeConfiguration(undefined, resolveConfiguration('', 'configs/configuration.json'))
@@ -27,11 +25,12 @@ it('Should have empty changelog (tags)', async () => {
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration
configuration,
repositoryUtils: githubRepository
}
let data: any
if (enablePullData) {
data = await pullData(octokit, options)
data = await pullData(githubRepository, options)
} else {
data = checkExportedData(false, 'caches/rcba_0.0.2-0.0.3_cache.json')
}
@@ -54,11 +53,12 @@ it('Should match generated changelog (tags)', async () => {
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration
configuration,
repositoryUtils: githubRepository
}
let data: any
if (enablePullData) {
data = await pullData(octokit, options)
data = await pullData(githubRepository, options)
} else {
data = checkExportedData(false, 'caches/rcba_0.0.1-0.0.3_cache.json')
}
@@ -87,11 +87,12 @@ it('Should match generated changelog (refs)', async () => {
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration
configuration,
repositoryUtils: githubRepository
}
let data: any
if (enablePullData) {
data = await pullData(octokit, options)
data = await pullData(githubRepository, options)
} else {
data = checkExportedData(false, 'caches/rcba_5ec7a2-fa3788_cache.json')
}
@@ -127,11 +128,12 @@ it('Should match generated changelog and replace all occurrences (refs)', async
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration
configuration,
repositoryUtils: githubRepository
}
let data: any
if (enablePullData) {
data = await pullData(octokit, options)
data = await pullData(githubRepository, options)
} else {
data = checkExportedData(false, 'caches/rcba_5ec7a2-fa3788_cache.json')
}
@@ -170,11 +172,12 @@ it('Should match ordered ASC', async () => {
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration
configuration,
repositoryUtils: githubRepository
}
let data: any
if (enablePullData) {
data = await pullData(octokit, options)
data = await pullData(githubRepository, options)
} else {
data = checkExportedData(false, 'caches/rcba_0.3.0-0.5.0_cache.json')
}
@@ -198,11 +201,12 @@ it('Should match ordered DESC', async () => {
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration
configuration,
repositoryUtils: githubRepository
}
let data: any
if (enablePullData) {
data = await pullData(octokit, options)
data = await pullData(githubRepository, options)
} else {
data = checkExportedData(false, 'caches/rcba_0.3.0-0.5.0_cache.json')
}
@@ -225,11 +229,12 @@ it('Should match ordered by title ASC', async () => {
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration
configuration,
repositoryUtils: githubRepository
}
let data: any
if (enablePullData) {
data = await pullData(octokit, options)
data = await pullData(githubRepository, options)
} else {
data = checkExportedData(false, 'caches/rcba_0.3.0-0.5.0_cache.json')
}
@@ -254,11 +259,12 @@ it('Should match ordered by title DESC', async () => {
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration
configuration,
repositoryUtils: githubRepository
}
let data: any
if (enablePullData) {
data = await pullData(octokit, options)
data = await pullData(githubRepository, options)
} else {
data = checkExportedData(false, 'caches/rcba_0.3.0-0.5.0_cache.json')
}
@@ -283,11 +289,12 @@ it('Should ignore PRs not merged into develop branch', async () => {
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration
configuration,
repositoryUtils: githubRepository
}
let data: any
if (enablePullData) {
data = await pullData(octokit, options)
data = await pullData(githubRepository, options)
} else {
data = checkExportedData(false, 'caches/rcba_1.3.1-1.4.0_base_develop_cache.json')
}
@@ -310,11 +317,12 @@ it('Should ignore PRs not merged into main branch', async () => {
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration
configuration,
repositoryUtils: githubRepository
}
let data: any
if (enablePullData) {
data = await pullData(octokit, options)
data = await pullData(githubRepository, options)
} else {
data = checkExportedData(false, 'caches/rcba_1.3.1-1.4.0_base_main_cache.json')
}
+1 -1
View File
@@ -1,4 +1,4 @@
import {TagInfo, filterTags, prepareAndSortTags} from '../src/pr-collector/tags'
import {filterTags, prepareAndSortTags, TagInfo} from '../src/pr-collector/tags'
jest.setTimeout(180000)
+8 -3
View File
@@ -3,6 +3,7 @@ import moment from 'moment'
import {Configuration, DefaultConfiguration} from '../src/configuration'
import {PullRequestInfo} from '../src/pr-collector/pullRequests'
import {DefaultDiffInfo} from '../src/pr-collector/commits'
import {GithubRepository} from '../src/repositories/GithubRepository'
jest.setTimeout(180000)
@@ -437,6 +438,7 @@ it('Use empty_content for empty category', async () => {
)
})
const repositoryUtils = new GithubRepository(process.env.GITEA_TOKEN || '', undefined, '.')
it('Commit SHA-1 in commitMode', async () => {
const customConfig = Object.assign({}, DefaultConfiguration)
customConfig.sort = 'DESC'
@@ -453,7 +455,8 @@ it('Commit SHA-1 in commitMode', async () => {
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: true,
configuration: customConfig
configuration: customConfig,
repositoryUtils: repositoryUtils
})
expect(resultChangelog).toStrictEqual(`## 🚀 Features\n\nsha1-3\nsha1-1\n\n## 🐛 Fixes\n\nsha1-3\nsha1-2\n\n`)
@@ -474,7 +477,8 @@ it('Release Diff', async () => {
fetchReleaseInformation: true,
fetchReviews: false,
commitMode: true,
configuration: customConfig
configuration: customConfig,
repositoryUtils: repositoryUtils
})
expect(resultChangelog).toStrictEqual(`https://github.com/mikepenz/release-changelog-builder-action/compare/v2.8.0...v2.8.1\n`)
@@ -678,6 +682,7 @@ function buildChangelogTest(config: Configuration, prs: PullRequestInfo[]): stri
fetchReleaseInformation: false,
fetchReviews: false,
commitMode: false,
configuration: config
configuration: config,
repositoryUtils: repositoryUtils
})
}
+3
View File
@@ -58,6 +58,9 @@ inputs:
default: "false"
cache:
description: 'Provide the cache of a previous run. Allows to re-use collected information multiple times to generate different release notes. Requires `exportCache` to be enabled for the previous run.'
platform:
description: 'Defines the platform the action is run on. Available options: [`github`, `gitea`]. Defaults to `github`.'
default: "github"
outputs:
changelog:
description: The built release changelog built from the merged pull requests
+708
View File
@@ -0,0 +1,708 @@
{
"mergedPullRequests": [
{
"number": 1,
"title": "Clean up and polish",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/1",
"baseBranch": "master",
"branch": "20df4b7f69f8dc609e98e3274739b49dc756884c",
"mergedAt": "2020-02-18T05:27:54.000Z",
"mergeCommitSha": "427ecdb7f1f4e289cb820ce2fbafe158b9b30012",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"enhancement"
],
"milestone": "0.1.1",
"body": "",
"approvedReviewers": [],
"createdAt": "2020-02-18T05:27:13.000Z",
"status": "merged"
},
{
"number": 2,
"title": "Add Drone and releases",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/2",
"baseBranch": "master",
"branch": "427ecdb7f1f4e289cb820ce2fbafe158b9b30012",
"mergedAt": "2020-02-18T15:51:14.000Z",
"mergeCommitSha": "5929bebe01e7b8c7c57b3c8fdfd41d4038bb85a1",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"build"
],
"milestone": "0.2.0",
"body": "",
"approvedReviewers": [],
"createdAt": "2020-02-18T15:41:58.000Z",
"status": "merged"
},
{
"number": 6,
"title": "Update Beaver and fix bugs",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/6",
"baseBranch": "master",
"branch": "5929bebe01e7b8c7c57b3c8fdfd41d4038bb85a1",
"mergedAt": "2020-02-27T02:53:14.000Z",
"mergeCommitSha": "bb773780df3488204df93228bdd72eb59418029b",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"bug"
],
"milestone": "0.2.0",
"body": "Fixes #3 \nFixes #4 \nFixes #5",
"approvedReviewers": [],
"createdAt": "2020-02-27T02:45:46.000Z",
"status": "merged"
},
{
"number": 7,
"title": "Fix PR head nil panic",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/7",
"baseBranch": "master",
"branch": "bb773780df3488204df93228bdd72eb59418029b",
"mergedAt": "2020-02-27T03:03:34.000Z",
"mergeCommitSha": "1956062791dae3e66c0c11d6fa86c59b031e51ee",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"bug"
],
"milestone": "0.2.0",
"body": "When checking PR status, retrieved PRs may have a nil head if the branch has been deleted.",
"approvedReviewers": [],
"createdAt": "2020-02-27T03:01:09.000Z",
"status": "merged"
},
{
"number": 8,
"title": "Add search filters",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/8",
"baseBranch": "master",
"branch": "1956062791dae3e66c0c11d6fa86c59b031e51ee",
"mergedAt": "2020-02-27T04:58:04.000Z",
"mergeCommitSha": "df58f223f25edd30ce8d15328d9d99fc9f98954b",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"enhancement"
],
"milestone": "0.2.0",
"body": "Adds search filters for state, author, labels, and milestone\n\nCheck the updated README for more details.",
"approvedReviewers": [],
"createdAt": "2020-02-27T04:39:37.000Z",
"status": "merged"
},
{
"number": 9,
"title": "Changelog 0.2.0",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/9",
"baseBranch": "master",
"branch": "df58f223f25edd30ce8d15328d9d99fc9f98954b",
"mergedAt": "2020-02-27T05:20:31.000Z",
"mergeCommitSha": "222dcf402b1cc0b57dbd4e2e9bc34196410c8a6b",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"docs"
],
"milestone": "0.2.0",
"body": "As title",
"approvedReviewers": [],
"createdAt": "2020-02-27T05:17:31.000Z",
"status": "merged"
},
{
"number": 10,
"title": "Add qualifier module",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/10",
"baseBranch": "master",
"branch": "222dcf402b1cc0b57dbd4e2e9bc34196410c8a6b",
"mergedAt": "2020-03-06T04:18:38.000Z",
"mergeCommitSha": "4490cc9888b4e39e14ce1c8fe9bdf64de348de71",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"enhancement"
],
"milestone": "0.2.1",
"body": "Better support for search query qualifiers",
"approvedReviewers": [],
"createdAt": "2020-02-28T03:33:43.000Z",
"status": "merged"
},
{
"number": 13,
"title": "Add create repo command",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/13",
"baseBranch": "master",
"branch": "4490cc9888b4e39e14ce1c8fe9bdf64de348de71",
"mergedAt": "2020-03-06T04:21:58.000Z",
"mergeCommitSha": "03fb319d3989c68a39c0652d8ff972e0957c5e6c",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"feature"
],
"milestone": "0.3.0",
"body": "Resolves #12",
"approvedReviewers": [],
"createdAt": "2020-03-06T04:17:46.000Z",
"status": "merged"
},
{
"number": 14,
"title": "Fix Drone release",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/14",
"baseBranch": "master",
"branch": "03fb319d3989c68a39c0652d8ff972e0957c5e6c",
"mergedAt": "2020-03-31T20:17:02.000Z",
"mergeCommitSha": "5ea204fb61cdb30501f8a6686b7132473f743b69",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"build"
],
"milestone": "0.2.1",
"body": "\r\nSigned-off-by: jolheiser <john.olheiser@gmail.com>",
"approvedReviewers": [],
"createdAt": "2020-03-31T20:11:46.000Z",
"status": "merged"
},
{
"number": 16,
"title": "Add release support and CSV output",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/16",
"baseBranch": "master",
"branch": "5ea204fb61cdb30501f8a6686b7132473f743b69",
"mergedAt": "2020-04-17T03:59:15.000Z",
"mergeCommitSha": "0a6162ad05900394d381eef9ec05704b3941c5c4",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"feature"
],
"milestone": "0.3.0",
"body": "Resolves #15\r\n\r\nThis PR adds support for listing and creating releases.\r\n\r\nIt also adds a `--csv <file>` flag to issue/PR/release searches, which will instead dump CSV-formatting information to the specified file.",
"approvedReviewers": [],
"createdAt": "2020-04-17T03:54:27.000Z",
"status": "merged"
},
{
"number": 17,
"title": "Imp formatting",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/17",
"baseBranch": "master",
"branch": "0a6162ad05900394d381eef9ec05704b3941c5c4",
"mergedAt": "2020-05-07T01:09:33.000Z",
"mergeCommitSha": "448e12ce38128909c32f30b29dc560ac44d1d7a5",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"docs"
],
"milestone": "0.3.0",
"body": "This PR is the result of running [imp](https://gitea.com/jolheiser/imp) against the repo.",
"approvedReviewers": [],
"createdAt": "2020-05-07T01:07:19.000Z",
"status": "merged"
},
{
"number": 19,
"title": "Update Gitea SDK and other modules",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/19",
"baseBranch": "master",
"branch": "448e12ce38128909c32f30b29dc560ac44d1d7a5",
"mergedAt": "2020-07-15T18:15:49.000Z",
"mergeCommitSha": "e4303d76389f45d9d7a5da29b504200038c46eb4",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"enhancement"
],
"milestone": "0.3.0",
"body": "As title",
"approvedReviewers": [],
"createdAt": "2020-05-28T03:21:56.000Z",
"status": "merged"
},
{
"number": 20,
"title": "Update modules",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/20",
"baseBranch": "master",
"branch": "e4303d76389f45d9d7a5da29b504200038c46eb4",
"mergedAt": "2020-09-13T03:59:45.000Z",
"mergeCommitSha": "dac69ffbd020f83a39b8fadcf3dcb928ed0826f1",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"build"
],
"milestone": "0.4.0",
"body": "",
"approvedReviewers": [],
"createdAt": "2020-09-13T03:36:59.000Z",
"status": "merged"
},
{
"number": 21,
"title": "Add open functionality",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/21",
"baseBranch": "master",
"branch": "dac69ffbd020f83a39b8fadcf3dcb928ed0826f1",
"mergedAt": "2020-09-13T04:34:13.000Z",
"mergeCommitSha": "b4d7ff5775e913e3681c6c2f1009e37591a060cf",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"feature"
],
"milestone": "0.4.0",
"body": "Closes #11\n\nThis PR adds functionality to open a repo/issue/PR\n\nTo open the current repo `sip open`\n\nTo open an issue `sip open 1234`\n\nTo open a different repo `sip open jolheiser/vanity`",
"approvedReviewers": [],
"createdAt": "2020-09-13T04:23:10.000Z",
"status": "merged"
},
{
"number": 22,
"title": "Add changelog for 0.3.0 and 0.4.0",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/22",
"baseBranch": "master",
"branch": "b4d7ff5775e913e3681c6c2f1009e37591a060cf",
"mergedAt": "2020-09-13T04:42:13.000Z",
"mergeCommitSha": "40e256e8b9da14692f348ec10db17f773569c66f",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"docs",
"skip-changelog"
],
"milestone": "0.4.0",
"body": "",
"approvedReviewers": [],
"createdAt": "2020-09-13T04:41:50.000Z",
"status": "merged"
},
{
"number": 23,
"title": "Update Gitea SDK",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/23",
"baseBranch": "master",
"branch": "40e256e8b9da14692f348ec10db17f773569c66f",
"mergedAt": "2020-09-15T18:02:46.000Z",
"mergeCommitSha": "8db0c08253f7e30ef86a8ba67169ea4d3e4cf72b",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"build"
],
"milestone": "0.5.0",
"body": "",
"approvedReviewers": [],
"createdAt": "2020-09-15T17:57:59.000Z",
"status": "merged"
},
{
"number": 24,
"title": "Update repo info",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/24",
"baseBranch": "master",
"branch": "8db0c08253f7e30ef86a8ba67169ea4d3e4cf72b",
"mergedAt": "2020-09-16T03:54:50.000Z",
"mergeCommitSha": "3e49adf6047960a03f53346bbececb3ce7e0809b",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"enhancement"
],
"milestone": "0.5.0",
"body": "Now that the SDK supports forks, watchers, stars, etc.\n\nThis PR updates the `sip repo` information",
"approvedReviewers": [],
"createdAt": "2020-09-16T03:48:01.000Z",
"status": "merged"
},
{
"number": 26,
"title": "Add release attachments",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/26",
"baseBranch": "master",
"branch": "3e49adf6047960a03f53346bbececb3ce7e0809b",
"mergedAt": "2020-09-16T18:07:32.000Z",
"mergeCommitSha": "a51305f8162b0a5ec80387db0b5ecc8a89e209be",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"enhancement"
],
"milestone": "0.5.0",
"body": "Resolves #25",
"approvedReviewers": [],
"createdAt": "2020-09-16T17:57:57.000Z",
"status": "merged"
},
{
"number": 29,
"title": "Refactor",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/29",
"baseBranch": "master",
"branch": "a51305f8162b0a5ec80387db0b5ecc8a89e209be",
"mergedAt": "2020-09-17T16:25:11.000Z",
"mergeCommitSha": "894a641ef86c444dccfa55eca457186b5e10da95",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"enhancement"
],
"milestone": "0.5.0",
"body": "Fixes #27\n\nFixes #28\n\nThis PR refactors and cleans up packages.\n\nIt also scans CLI flags into variables for fewer footguns.",
"approvedReviewers": [],
"createdAt": "2020-09-17T04:11:50.000Z",
"status": "merged"
},
{
"number": 30,
"title": "Changelog 0.5.0",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/30",
"baseBranch": "master",
"branch": "894a641ef86c444dccfa55eca457186b5e10da95",
"mergedAt": "2020-09-17T16:34:42.000Z",
"mergeCommitSha": "cce2360f0fcec4f63c66e5b05bac25a7ba42f942",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"docs"
],
"milestone": "0.5.0",
"body": "## [0.5.0](https://gitea.com/jolheiser/sip/pulls?q=&type=all&state=closed&milestone=1311) - 2020-09-17\r\n\r\n<details><summary>ENHANCEMENTS</summary>\r\n\r\n* Refactor (#29)\r\n* Add release attachments (#26)\r\n* Update repo info (#24)\r\n</details>\r\n<details><summary>BUILD</summary>\r\n\r\n* Update Gitea SDK (#23)\r\n</details>\r\n",
"approvedReviewers": [],
"createdAt": "2020-09-17T16:34:05.000Z",
"status": "merged"
},
{
"number": 36,
"title": "Add attachment removal and change message",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/36",
"baseBranch": "master",
"branch": "cce2360f0fcec4f63c66e5b05bac25a7ba42f942",
"mergedAt": "2020-09-21T14:19:38.000Z",
"mergeCommitSha": "0bbe2e35ff5b482bae10ecf7abcd89815274c217",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"enhancement"
],
"milestone": "0.5.1",
"body": "Fixes #35\r\n\r\nChanges the message to instead tell the user how many files were added/removed from the release.\r\n\r\nThis PR also adds a way to multi-select attachments to be removed from a release via `sip release attach remove` since `sip release remove` will be reserved for removing a release in the future.",
"approvedReviewers": [],
"createdAt": "2020-09-21T03:59:49.000Z",
"status": "merged"
},
{
"number": 37,
"title": "Change to vanity URL",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/37",
"baseBranch": "master",
"branch": "0bbe2e35ff5b482bae10ecf7abcd89815274c217",
"mergedAt": "2020-09-21T19:21:09.000Z",
"mergeCommitSha": "5ecbcde5180e4a3b12bdc35416c2f050cd0808f1",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"build"
],
"milestone": "",
"body": "",
"approvedReviewers": [],
"createdAt": "2020-09-21T04:07:33.000Z",
"status": "merged"
}
],
"diffInfo": {
"changedFiles": 43,
"additions": 1942,
"deletions": 418,
"changes": 0,
"commits": 24,
"commitInfo": [
{
"sha": "427ecdb7f1f4e289cb820ce2fbafe158b9b30012",
"summary": "Clean up and polish (#1)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-02-18T05:27:52.000Z",
"committer": "John Olheiser",
"commitDate": "2020-02-18T05:27:52.000Z"
},
{
"sha": "5929bebe01e7b8c7c57b3c8fdfd41d4038bb85a1",
"summary": "Add Drone and releases (#2)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-02-18T15:51:10.000Z",
"committer": "John Olheiser",
"commitDate": "2020-02-18T15:51:10.000Z"
},
{
"sha": "bb773780df3488204df93228bdd72eb59418029b",
"summary": "Update Beaver and fix bugs (#6)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-02-27T02:53:11.000Z",
"committer": "John Olheiser",
"commitDate": "2020-02-27T02:53:11.000Z"
},
{
"sha": "1956062791dae3e66c0c11d6fa86c59b031e51ee",
"summary": "Fix PR head nil panic (#7)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-02-27T03:03:32.000Z",
"committer": "John Olheiser",
"commitDate": "2020-02-27T03:03:32.000Z"
},
{
"sha": "df58f223f25edd30ce8d15328d9d99fc9f98954b",
"summary": "Add search filters (#8)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-02-27T04:58:02.000Z",
"committer": "John Olheiser",
"commitDate": "2020-02-27T04:58:02.000Z"
},
{
"sha": "222dcf402b1cc0b57dbd4e2e9bc34196410c8a6b",
"summary": "Changelog 0.2.0 (#9)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-02-27T05:20:29.000Z",
"committer": "John Olheiser",
"commitDate": "2020-02-27T05:20:29.000Z"
},
{
"sha": "4490cc9888b4e39e14ce1c8fe9bdf64de348de71",
"summary": "Add qualifier module (#10)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-03-06T04:18:36.000Z",
"committer": "John Olheiser",
"commitDate": "2020-03-06T04:18:36.000Z"
},
{
"sha": "03fb319d3989c68a39c0652d8ff972e0957c5e6c",
"summary": "Add create repo command (#13)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-03-06T04:21:56.000Z",
"committer": "John Olheiser",
"commitDate": "2020-03-06T04:21:56.000Z"
},
{
"sha": "64b0335e0ae45a4bd264bbab008551b7820f8811",
"summary": "Fix Drone release",
"message": "",
"author": "jolheiser",
"authorDate": "2020-03-31T20:10:18.000Z",
"committer": "jolheiser",
"commitDate": "2020-03-31T20:10:18.000Z"
},
{
"sha": "5ea204fb61cdb30501f8a6686b7132473f743b69",
"summary": "Merge pull request 'Fix Drone release' (#14) from drone-release into master",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-03-31T20:17:01.000Z",
"committer": "John Olheiser",
"commitDate": "2020-03-31T20:17:01.000Z"
},
{
"sha": "0a6162ad05900394d381eef9ec05704b3941c5c4",
"summary": "Add release support and CSV output (#16)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-04-17T03:59:12.000Z",
"committer": "John Olheiser",
"commitDate": "2020-04-17T03:59:12.000Z"
},
{
"sha": "448e12ce38128909c32f30b29dc560ac44d1d7a5",
"summary": "Imp formatting (#17)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-05-07T01:09:31.000Z",
"committer": "John Olheiser",
"commitDate": "2020-05-07T01:09:31.000Z"
},
{
"sha": "e4303d76389f45d9d7a5da29b504200038c46eb4",
"summary": "Update Gitea SDK and other modules (#19)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-07-15T18:15:46.000Z",
"committer": "John Olheiser",
"commitDate": "2020-07-15T18:15:46.000Z"
},
{
"sha": "dac69ffbd020f83a39b8fadcf3dcb928ed0826f1",
"summary": "Update modules (#20)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-13T03:59:43.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-13T03:59:43.000Z"
},
{
"sha": "b4d7ff5775e913e3681c6c2f1009e37591a060cf",
"summary": "Add open functionality (#21)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-13T04:34:11.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-13T04:34:11.000Z"
},
{
"sha": "40e256e8b9da14692f348ec10db17f773569c66f",
"summary": "Add changelog for 0.3.0 and 0.4.0 (#22)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-13T04:42:11.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-13T04:42:11.000Z"
},
{
"sha": "8db0c08253f7e30ef86a8ba67169ea4d3e4cf72b",
"summary": "Update Gitea SDK (#23)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-15T18:02:45.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-15T18:02:45.000Z"
},
{
"sha": "3e49adf6047960a03f53346bbececb3ce7e0809b",
"summary": "Update repo info (#24)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-16T03:54:48.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-16T03:54:48.000Z"
},
{
"sha": "a51305f8162b0a5ec80387db0b5ecc8a89e209be",
"summary": "Add release attachments (#26)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-16T18:07:30.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-16T18:07:30.000Z"
},
{
"sha": "894a641ef86c444dccfa55eca457186b5e10da95",
"summary": "Refactor (#29)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-17T16:25:09.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-17T16:25:09.000Z"
},
{
"sha": "cce2360f0fcec4f63c66e5b05bac25a7ba42f942",
"summary": "Changelog 0.5.0 (#30)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-17T16:34:40.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-17T16:34:40.000Z"
},
{
"sha": "0bbe2e35ff5b482bae10ecf7abcd89815274c217",
"summary": "Add attachment removal and change message (#36)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-21T14:19:36.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-21T14:19:36.000Z"
},
{
"sha": "5ecbcde5180e4a3b12bdc35416c2f050cd0808f1",
"summary": "Change to vanity URL (#37)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-21T19:21:07.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-21T19:21:07.000Z"
},
{
"sha": "1742fcc37c35faca189eae173cd803e9623a8b80",
"summary": "Fix drone-gitea-main (#38)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-21T19:30:21.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-21T19:30:21.000Z"
}
]
},
"options": {
"owner": "jolheiser",
"repo": "sip",
"fromTag": {
"name": "v0.1.0"
},
"toTag": {
"name": "master"
},
"includeOpen": false,
"failOnError": false,
"fetchViaCommits": false,
"fetchReviewers": false,
"fetchReleaseInformation": false,
"fetchReviews": false,
"commitMode": false,
"configuration": {
"max_tags_to_fetch": 200,
"max_pull_requests": 1000,
"max_back_track_time_days": 1000,
"exclude_merge_branches": [],
"sort": "ASC",
"template": "#{{CHANGELOG}}",
"pr_template": "- #{{TITLE}}\n - PR: ##{{NUMBER}}",
"empty_template": "- no changes",
"categories": [
{
"title": "## 🚀 Features",
"labels": [
"add",
"Add"
]
},
{
"title": "## 🐛 Fixes",
"labels": [
"fix",
"Fix"
]
}
],
"ignore_labels": [
"ignore"
],
"label_extractor": [
{
"pattern": "(\\w+) (.+)",
"target": "$1",
"on_property": "title"
}
],
"transformers": [],
"tag_resolver": {
"method": "semver"
},
"base_branches": [],
"custom_placeholders": [],
"trim_values": false
}
}
}
+167
View File
@@ -0,0 +1,167 @@
{
"mergedPullRequests": [
{
"number": 36,
"title": "Add attachment removal and change message",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/36",
"baseBranch": "master",
"branch": "cce2360f0fcec4f63c66e5b05bac25a7ba42f942",
"mergedAt": "2020-09-21T14:19:38.000Z",
"mergeCommitSha": "0bbe2e35ff5b482bae10ecf7abcd89815274c217",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"enhancement"
],
"milestone": "0.5.1",
"body": "Fixes #35\r\n\r\nChanges the message to instead tell the user how many files were added/removed from the release.\r\n\r\nThis PR also adds a way to multi-select attachments to be removed from a release via `sip release attach remove` since `sip release remove` will be reserved for removing a release in the future.",
"approvedReviewers": [],
"createdAt": "2020-09-21T03:59:49.000Z",
"status": "merged"
},
{
"number": 37,
"title": "Change to vanity URL",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/37",
"baseBranch": "master",
"branch": "0bbe2e35ff5b482bae10ecf7abcd89815274c217",
"mergedAt": "2020-09-21T19:21:09.000Z",
"mergeCommitSha": "5ecbcde5180e4a3b12bdc35416c2f050cd0808f1",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"build"
],
"milestone": "",
"body": "",
"approvedReviewers": [],
"createdAt": "2020-09-21T04:07:33.000Z",
"status": "merged"
},
{
"number": 38,
"title": "Fix drone-gitea-main",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/38",
"baseBranch": "master",
"branch": "5ecbcde5180e4a3b12bdc35416c2f050cd0808f1",
"mergedAt": "2020-09-21T19:30:23.000Z",
"mergeCommitSha": "1742fcc37c35faca189eae173cd803e9623a8b80",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"bug",
"build",
"skip-changelog"
],
"milestone": "0.5.1",
"body": "No `:1` tag exists for the image, only `latest`.",
"approvedReviewers": [],
"createdAt": "2020-09-21T19:30:06.000Z",
"status": "merged"
}
],
"diffInfo": {
"changedFiles": 24,
"additions": 160,
"deletions": 41,
"changes": 0,
"commits": 3,
"commitInfo": [
{
"sha": "0bbe2e35ff5b482bae10ecf7abcd89815274c217",
"summary": "Add attachment removal and change message (#36)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-21T14:19:36.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-21T14:19:36.000Z"
},
{
"sha": "5ecbcde5180e4a3b12bdc35416c2f050cd0808f1",
"summary": "Change to vanity URL (#37)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-21T19:21:07.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-21T19:21:07.000Z"
},
{
"sha": "1742fcc37c35faca189eae173cd803e9623a8b80",
"summary": "Fix drone-gitea-main (#38)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-21T19:30:21.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-21T19:30:21.000Z"
}
]
},
"options": {
"owner": "jolheiser",
"repo": "sip",
"fromTag": {
"name": "v0.5.0"
},
"toTag": {
"name": "master"
},
"includeOpen": false,
"failOnError": false,
"fetchViaCommits": true,
"fetchReviewers": false,
"fetchReleaseInformation": false,
"fetchReviews": false,
"commitMode": false,
"configuration": {
"max_tags_to_fetch": 200,
"max_pull_requests": 1000,
"max_back_track_time_days": 1000,
"exclude_merge_branches": [],
"sort": "ASC",
"template": "#{{CHANGELOG}}",
"pr_template": "- #{{TITLE}}\n - PR: ##{{NUMBER}}",
"empty_template": "- no changes",
"categories": [
{
"title": "## 🚀 Features",
"labels": [
"add",
"Add"
]
},
{
"title": "## 🐛 Fixes",
"labels": [
"fix",
"Fix"
]
},
{
"title": "## 🧪 Upgrade",
"labels": [
"upgrade",
"Upgrade",
"Clean"
]
}
],
"ignore_labels": [
"ignore"
],
"label_extractor": [
{
"pattern": "(\\w+) (.+)",
"target": "$1",
"on_property": "title"
}
],
"transformers": [],
"tag_resolver": {
"method": "semver"
},
"base_branches": [],
"custom_placeholders": [],
"trim_values": false
}
}
}
+134
View File
@@ -0,0 +1,134 @@
{
"mergedPullRequests": [
{
"number": 26,
"title": "Add release attachments",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/26",
"baseBranch": "master",
"branch": "3e49adf6047960a03f53346bbececb3ce7e0809b",
"mergedAt": "2020-09-16T18:07:32.000Z",
"mergeCommitSha": "a51305f8162b0a5ec80387db0b5ecc8a89e209be",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"enhancement"
],
"milestone": "0.5.0",
"body": "Resolves #25",
"approvedReviewers": [],
"createdAt": "2020-09-16T17:57:57.000Z",
"status": "merged"
},
{
"number": 29,
"title": "Refactor",
"htmlURL": "https://gitea.com/jolheiser/sip/pulls/29",
"baseBranch": "master",
"branch": "a51305f8162b0a5ec80387db0b5ecc8a89e209be",
"mergedAt": "2020-09-17T16:25:11.000Z",
"mergeCommitSha": "894a641ef86c444dccfa55eca457186b5e10da95",
"author": "jolheiser",
"repoName": "jolheiser/sip",
"labels": [
"enhancement"
],
"milestone": "0.5.0",
"body": "Fixes #27\n\nFixes #28\n\nThis PR refactors and cleans up packages.\n\nIt also scans CLI flags into variables for fewer footguns.",
"approvedReviewers": [],
"createdAt": "2020-09-17T04:11:50.000Z",
"status": "merged"
}
],
"diffInfo": {
"changedFiles": 36,
"additions": 576,
"deletions": 205,
"changes": 0,
"commits": 2,
"commitInfo": [
{
"sha": "a51305f8162b0a5ec80387db0b5ecc8a89e209be",
"summary": "Add release attachments (#26)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-16T18:07:30.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-16T18:07:30.000Z"
},
{
"sha": "894a641ef86c444dccfa55eca457186b5e10da95",
"summary": "Refactor (#29)",
"message": "",
"author": "John Olheiser",
"authorDate": "2020-09-17T16:25:09.000Z",
"committer": "John Olheiser",
"commitDate": "2020-09-17T16:25:09.000Z"
}
]
},
"options": {
"owner": "jolheiser",
"repo": "sip",
"fromTag": {
"name": "3e49adf6047960a03f53346bbececb3ce7e0809b"
},
"toTag": {
"name": "894a641ef86c444dccfa55eca457186b5e10da95"
},
"includeOpen": false,
"failOnError": false,
"fetchViaCommits": true,
"fetchReviewers": false,
"fetchReleaseInformation": false,
"fetchReviews": false,
"commitMode": false,
"configuration": {
"max_tags_to_fetch": 200,
"max_pull_requests": 1000,
"max_back_track_time_days": 1000,
"exclude_merge_branches": [],
"sort": {
"order": "ASC",
"on_property": "mergedAt"
},
"template": "#{{CHANGELOG}}",
"pr_template": "#{{TITLE}}\n#{{NUMBER}}\n#{{URL}}\n#{{MERGED_AT}}\n#{{AUTHOR}}\n#{{LABELS}}\n#{{MILESTONE}}\n#{{BODY}}\n#{{ASSIGNEES}}\n#{{REVIEWERS}}",
"empty_template": "- no changes",
"categories": [
{
"title": "## 🚀 Features",
"labels": [
"feature"
]
},
{
"title": "## 🐛 Fixes",
"labels": [
"fix"
]
},
{
"title": "## 🧪 Tests",
"labels": [
"test"
]
},
{
"title": "## 📦 Uncategorized",
"labels": []
}
],
"ignore_labels": [
"ignore"
],
"label_extractor": [],
"transformers": [],
"tag_resolver": {
"method": "semver"
},
"base_branches": [],
"custom_placeholders": [],
"trim_values": false
}
}
}
+29
View File
@@ -0,0 +1,29 @@
{
"categories": [
{
"title": "## 🚀 Features",
"labels": ["add","Add"]
},
{
"title": "## 🐛 Fixes",
"labels": ["fix","Fix"]
},
{
"title": "## 🧪 Upgrade",
"labels": ["upgrade","Upgrade","Clean"]
}
],
"label_extractor": [
{
"pattern": "(\\w+) (.+)",
"target": "$1",
"on_property": "title"
}
],
"sort": "ASC",
"template": "${{CHANGELOG}}",
"pr_template": "- ${{TITLE}}\n - PR: #${{NUMBER}}",
"empty_template": "- no changes",
"max_pull_requests": 1000,
"max_back_track_time_days": 1000
}
@@ -0,0 +1,29 @@
{
"categories": [
{
"title": "## 🚀 Features",
"labels": ["add","Add"]
},
{
"title": "## 🐛 Fixes",
"labels": ["fix","Fix"]
},
{
"title": "## 🧪 Upgrade",
"labels": ["upgrade","Upgrade","Clean"]
}
],
"label_extractor": [
{
"pattern": "(\\w+) (.+)",
"target": "$1",
"on_property": "title"
}
],
"sort": "DESC",
"template": "${{CHANGELOG}}",
"pr_template": "- ${{TITLE}}\n - PR: #${{NUMBER}}",
"empty_template": "- no changes",
"max_pull_requests": 1000,
"max_back_track_time_days": 1000
}
Generated Vendored
+6430 -388
View File
File diff suppressed because it is too large Load Diff
Generated Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
Generated Vendored
+25
View File
@@ -553,6 +553,31 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
gitea-js
MIT
MIT License
Copyright (c) 2022 Anbraten
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
has-flag
MIT
MIT License
+14 -8
View File
@@ -13,13 +13,14 @@
"@actions/exec": "^1.1.1",
"@actions/github": "^6.0.0",
"@octokit/rest": "^20.0.2",
"gitea-js": "^1.20.1",
"https-proxy-agent": "^7.0.2",
"moment": "^2.29.4",
"semver": "^7.5.4"
},
"devDependencies": {
"@types/jest": "^29.5.6",
"@types/node": "^20.8.7",
"@types/node": "^20.8.10",
"@types/semver": "^7.5.4",
"@typescript-eslint/eslint-plugin": "^6.8.0",
"@typescript-eslint/parser": "^6.8.0",
@@ -1619,12 +1620,12 @@
"dev": true
},
"node_modules/@types/node": {
"version": "20.8.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz",
"integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==",
"version": "20.8.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz",
"integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==",
"dev": true,
"dependencies": {
"undici-types": "~5.25.1"
"undici-types": "~5.26.4"
}
},
"node_modules/@types/semver": {
@@ -3924,6 +3925,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gitea-js": {
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/gitea-js/-/gitea-js-1.20.1.tgz",
"integrity": "sha512-g1wdNP5zYN258tTVIm2vGY8bRJTwVwCfYH0ockUpi34RAuOwJ0FavpFVVvazxXEcdo2XmXRKZcAmVhAhwMXkgg=="
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -6845,9 +6851,9 @@
}
},
"node_modules/undici-types": {
"version": "5.25.3",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz",
"integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==",
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/universal-user-agent": {
+7 -3
View File
@@ -6,12 +6,15 @@
"main": "lib/main.js",
"scripts": {
"build": "tsc",
"format": "prettier --write **/*.ts",
"format": "prettier --write **/*.ts **/**/*.ts",
"format-check": "prettier --check **/*.ts",
"format-fix": "eslint --fix src/**/*.ts",
"lint": "eslint src/**/*.ts",
"package": "ncc build --source-map --license licenses.txt",
"test": "jest",
"all": "npm run build && npm run format && npm run lint && npm run package && npm test"
"test-github": "jest __tests__/*.test.ts",
"test-gitea": "jest __tests__/gitea/*.test.ts",
"all": "npm run build && npm run format && npm run lint && npm run package && npm run test-github"
},
"repository": {
"type": "git",
@@ -36,13 +39,14 @@
"@actions/exec": "^1.1.1",
"@actions/github": "^6.0.0",
"@octokit/rest": "^20.0.2",
"gitea-js": "^1.20.1",
"https-proxy-agent": "^7.0.2",
"moment": "^2.29.4",
"semver": "^7.5.4"
},
"devDependencies": {
"@types/jest": "^29.5.6",
"@types/node": "^20.8.7",
"@types/node": "^20.8.10",
"@types/semver": "^7.5.4",
"@typescript-eslint/eslint-plugin": "^6.8.0",
"@typescript-eslint/parser": "^6.8.0",
+1 -1
View File
@@ -1,4 +1,4 @@
import {Rule, Extractor, Regex, Transformer, Sort, PullConfiguration} from './pr-collector/types'
import {Extractor, PullConfiguration, Regex, Rule, Sort, Transformer} from './pr-collector/types'
export interface Configuration extends PullConfiguration {
max_tags_to_fetch: number
+20 -3
View File
@@ -3,13 +3,29 @@ import * as github from '@actions/github'
import {mergeConfiguration, parseConfiguration, resolveConfiguration, retrieveRepositoryPath, writeOutput} from './utils'
import {ReleaseNotesBuilder} from './releaseNotesBuilder'
import {Configuration} from './configuration'
import {GithubRepository} from './repositories/GithubRepository'
import {GiteaRepository} from './repositories/GiteaRepository'
async function run(): Promise<void> {
core.setOutput('failed', false) // mark the action not failed by default
const supportedPlatform = {
github: GithubRepository,
gitea: GiteaRepository
}
function isSupportedPlatform(type: string): type is keyof typeof supportedPlatform {
return type in supportedPlatform
}
core.setOutput('failed', false) // mark the action not failed by default
core.startGroup(`📘 Reading input values`)
try {
// read in path specification, resolve github workspace, and repo path
const platform = core.getInput('platform') || 'github'
if (!isSupportedPlatform(platform)) {
core.setFailed(`The ${platform} platform is not supported. `)
return
}
const inputPath = core.getInput('path')
const repositoryPath = retrieveRepositoryPath(inputPath)
@@ -40,7 +56,7 @@ async function run(): Promise<void> {
// read in repository inputs
const baseUrl = core.getInput('baseUrl')
const token = core.getInput('token')
const token = core.getInput('token') || process.env.GITHUB_TOKEN || ''
const owner = core.getInput('owner') || github.context.repo.owner
const repo = core.getInput('repo') || github.context.repo.repo
// read in from, to tag inputs
@@ -59,9 +75,10 @@ async function run(): Promise<void> {
const exportOnly = core.getInput('exportOnly') === 'true'
const cache = core.getInput('cache')
const repositoryUtils = new supportedPlatform[platform](token, baseUrl, repositoryPath)
const result = await new ReleaseNotesBuilder(
baseUrl,
token,
repositoryUtils,
repositoryPath,
owner,
repo,
-1
View File
@@ -1 +0,0 @@
../pr-collector/src/
+4 -59
View File
@@ -1,9 +1,9 @@
import * as core from '@actions/core'
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
import moment from 'moment'
import {failOrError} from './utils'
import {PullRequestInfo} from './pullRequests'
import {Options} from './prCollector'
import {BaseRepository} from '../repositories/BaseRepository'
export interface DiffInfo {
changedFiles: number
@@ -34,7 +34,7 @@ export interface CommitInfo {
}
export class Commits {
constructor(private octokit: Octokit) {}
constructor(private repositoryUtils: BaseRepository) {}
async getDiff(owner: string, repo: string, base: string, head: string): Promise<DiffInfo> {
const diff: DiffInfo = await this.getDiffRemote(owner, repo, base, head)
@@ -43,62 +43,7 @@ export class Commits {
}
private async getDiffRemote(owner: string, repo: string, base: string, head: string): Promise<DiffInfo> {
let changedFilesCount = 0
let additionCount = 0
let deletionCount = 0
let changeCount = 0
let commitCount = 0
// Fetch comparisons recursively until we don't find any commits
// This is because the GitHub API limits the number of commits returned in a single response.
let commits: RestEndpointMethodTypes['repos']['compareCommits']['response']['data']['commits'] = []
let compareHead = head
// eslint-disable-next-line no-constant-condition
while (true) {
const compareResult = await this.octokit.repos.compareCommits({
owner,
repo,
base,
head: compareHead
})
if (compareResult.data.total_commits === 0) {
break
}
changedFilesCount += compareResult.data.files?.length ?? 0
const files = compareResult.data.files
if (files !== undefined) {
for (const file of files) {
additionCount += file.additions
deletionCount += file.deletions
changeCount += file.changes
}
}
commitCount += compareResult.data.commits.length
commits = compareResult.data.commits.concat(commits)
compareHead = `${commits[0].sha}^`
}
core.info(`️ Found ${commits.length} commits from the GitHub API for ${owner}/${repo}`)
return {
changedFiles: changedFilesCount,
additions: additionCount,
deletions: deletionCount,
changes: changeCount,
commits: commitCount,
commitInfo: commits
.filter(commit => commit.sha)
.map(commit => ({
sha: commit.sha || '',
summary: commit.commit.message.split('\n')[0],
message: commit.commit.message,
author: commit.author?.login || '',
authorDate: moment(commit.commit.author?.date),
committer: commit.committer?.login || '',
commitDate: moment(commit.commit.committer?.date),
prNumber: undefined
}))
}
return this.repositoryUtils.getDiffRemote(owner, repo, base, head)
}
private sortCommits(commits: CommitInfo[]): CommitInfo[] {
@@ -129,7 +74,7 @@ export class Commits {
const {owner, repo, fromTag, toTag, failOnError} = options
core.info(`️ Comparing ${owner}/${repo} - '${fromTag.name}...${toTag.name}'`)
const commitsApi = new Commits(this.octokit)
const commitsApi = new Commits(this.repositoryUtils)
let diffInfo: DiffInfo
try {
diffInfo = await commitsApi.getDiff(owner, repo, fromTag.name, toTag.name)
@@ -39,7 +39,7 @@ class GitCommandManager {
return result
}
private async execGit(args: string[], allowAllExitCodes = false, silent = false): Promise<GitOutput> {
async execGit(args: string[], allowAllExitCodes = false, silent = false): Promise<GitOutput> {
directoryExistsSync(this.workingDirectory, true)
const result = new GitOutput()
@@ -1,11 +1,10 @@
import * as core from '@actions/core'
import {PullConfiguration} from './types'
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'
import {BaseRepository} from '../repositories/BaseRepository'
export interface Options {
owner: string // the owner of the repository
@@ -32,7 +31,7 @@ export interface Data {
export class PullRequestCollector {
constructor(
private baseUrl: string | null,
private token: string | null,
private repositoryUtils: BaseRepository,
private repositoryPath: string,
private owner: string,
private repo: string,
@@ -51,32 +50,10 @@ export class PullRequestCollector {
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 tagsApi = new Tags(this.repositoryUtils)
const tagRange = await tagsApi.retrieveRange(
this.repositoryPath,
this.owner,
@@ -114,7 +91,7 @@ export class PullRequestCollector {
core.endGroup()
return await pullData(octokit, {
return await pullData(this.repositoryUtils, {
owner: this.owner,
repo: this.repo,
fromTag: previousTag,
@@ -131,14 +108,14 @@ export class PullRequestCollector {
}
}
export async function pullData(octokit: Octokit, options: Options): Promise<Data | null> {
export async function pullData(repositoryUtils: BaseRepository, options: Options): Promise<Data | null> {
let mergedPullRequests: PullRequestInfo[]
let diffInfo: DiffInfo
const commitsApi = new Commits(octokit)
const commitsApi = new Commits(repositoryUtils)
if (!options.commitMode) {
core.startGroup(`🚀 Load pull requests`)
const pullRequestsApi = new PullRequests(octokit, commitsApi)
const pullRequestsApi = new PullRequests(repositoryUtils, commitsApi)
const [info, prs] = await pullRequestsApi.getMergedPullRequests(options)
mergedPullRequests = prs
diffInfo = info
+10 -164
View File
@@ -1,10 +1,10 @@
import * as core from '@actions/core'
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
import {Unpacked} from './utils'
import {RestEndpointMethodTypes} from '@octokit/rest'
import moment from 'moment'
import {Property, Sort} from './types'
import {Commits, DiffInfo, filterCommits} from './commits'
import {Options} from './prCollector'
import {BaseRepository} from '../repositories/BaseRepository'
export interface PullRequestInfo {
number: number
@@ -64,53 +64,20 @@ export const EMPTY_COMMENT_INFO: CommentInfo = {
state: undefined
}
type PullData = RestEndpointMethodTypes['pulls']['get']['response']['data']
export type PullData = RestEndpointMethodTypes['pulls']['get']['response']['data']
type PullsListData = RestEndpointMethodTypes['pulls']['list']['response']['data']
export type PullsListData = RestEndpointMethodTypes['pulls']['list']['response']['data']
type PullReviewsData = RestEndpointMethodTypes['pulls']['listReviews']['response']['data']
export type PullReviewsData = RestEndpointMethodTypes['pulls']['listReviews']['response']['data']
export class PullRequests {
constructor(
private octokit: Octokit,
private repositoryUtils: BaseRepository,
private commits: Commits
) {}
async getSingle(owner: string, repo: string, prNumber: number): Promise<PullRequestInfo | null> {
try {
const {data} = await this.octokit.pulls.get({
owner,
repo,
pull_number: prNumber
})
return mapPullRequest(data)
} catch (e: any /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
core.warning(`⚠️ Cannot find PR ${owner}/${repo}#${prNumber} - ${e.message}`)
return null
}
}
async getForCommitHash(owner: string, repo: string, commit_sha: string, maxPullRequests: number): Promise<PullRequestInfo[]> {
const mergedPRs: PullRequestInfo[] = []
const options = this.octokit.repos.listPullRequestsAssociatedWithCommit.endpoint.merge({
owner,
repo,
commit_sha,
per_page: `${Math.min(10, maxPullRequests)}`,
direction: 'desc'
})
for await (const response of this.octokit.paginate.iterator(options)) {
const prs: PullsListData = response.data as PullsListData
for (const pr of prs) {
mergedPRs.push(mapPullRequest(pr, pr.merged_at ? 'merged' : 'open'))
}
}
return sortPrs(mergedPRs)
return sortPrs(await this.repositoryUtils.getForCommitHash(owner, repo, commit_sha, maxPullRequests))
}
async getBetweenDates(
@@ -120,86 +87,15 @@ export class PullRequests {
toDate: moment.Moment,
maxPullRequests: number
): Promise<PullRequestInfo[]> {
const mergedPRs: PullRequestInfo[] = []
const options = this.octokit.pulls.list.endpoint.merge({
owner,
repo,
state: 'closed',
sort: 'merged',
per_page: `${Math.min(100, maxPullRequests)}`,
direction: 'desc'
})
for await (const response of this.octokit.paginate.iterator(options)) {
const prs: PullsListData = response.data as PullsListData
for (const pr of prs.filter(p => !!p.merged_at)) {
mergedPRs.push(mapPullRequest(pr, 'merged'))
}
if (mergedPRs.length >= maxPullRequests) {
core.warning(`⚠️ Reached 'maxPullRequests' count ${maxPullRequests} (1)`)
break // bail out early to not keep iterating forever
} else if (prs.length > 0) {
if (fetchedEnough(prs, fromDate)) {
return sortPrs(mergedPRs) // bail out early to not keep iterating on PRs super old
}
} else {
core.debug(`⚠️ No more PRs retrieved from API. Fetched so far: ${mergedPRs.length}`)
break
}
}
return sortPrs(mergedPRs)
return sortPrs(await this.repositoryUtils.getBetweenDates(owner, repo, fromDate, toDate, maxPullRequests))
}
async getOpen(owner: string, repo: string, maxPullRequests: number): Promise<PullRequestInfo[]> {
const openPrs: PullRequestInfo[] = []
const options = this.octokit.pulls.list.endpoint.merge({
owner,
repo,
state: 'open',
sort: 'created',
per_page: '100',
direction: 'desc'
})
for await (const response of this.octokit.paginate.iterator(options)) {
const prs: PullsListData = response.data as PullsListData
for (const pr of prs) {
openPrs.push(mapPullRequest(pr, 'open'))
}
const firstPR = prs[0]
if (firstPR === undefined || openPrs.length >= maxPullRequests) {
if (openPrs.length >= maxPullRequests) {
core.warning(`⚠️ Reached 'maxPullRequests' count ${maxPullRequests} (2)`)
}
break // bail out early to not keep iterating forever
}
}
return sortPrs(openPrs)
return sortPrs(await this.repositoryUtils.getOpen(owner, repo, maxPullRequests))
}
async getReviews(owner: string, repo: string, pr: PullRequestInfo): Promise<void> {
const options = this.octokit.pulls.listReviews.endpoint.merge({
owner,
repo,
pull_number: pr.number,
sort: 'created',
direction: 'desc'
})
const prReviews: CommentInfo[] = []
for await (const response of this.octokit.paginate.iterator(options)) {
const comments: PullReviewsData = response.data as PullReviewsData
for (const comment of comments) {
prReviews.push(mapComment(comment))
}
}
pr.reviews = prReviews
await this.repositoryUtils.getReviews(owner, repo, pr)
}
async getMergedPullRequests(options: Options): Promise<[DiffInfo, PullRequestInfo[]]> {
@@ -323,20 +219,6 @@ export class PullRequests {
}
}
function fetchedEnough(pullRequests: PullsListData, fromDate: moment.Moment): boolean {
for (let i = 0; i < Math.min(pullRequests.length, 3); i++) {
const firstPR = pullRequests[i]
if (!firstPR.merged_at) {
continue // no merged_at timestamp -> look for the next
} else if (fromDate.isAfter(moment(firstPR.merged_at))) {
return true
} else {
break // not enough PRs yet, go further
}
}
return false
}
function sortPrs(pullRequests: PullRequestInfo[]): PullRequestInfo[] {
return sortPullRequests(pullRequests, {
order: 'ASC',
@@ -401,39 +283,3 @@ export function retrieveProperty(pr: PullRequestInfo, property: Property, useCas
}
return value
}
// helper function to add a special open label to prs not merged.
function attachSpeciaLabels(status: 'open' | 'merged', labels: string[]): string[] {
labels.push(`--rcba-${status}`)
return labels
}
const mapPullRequest = (pr: PullData | Unpacked<PullsListData>, status: 'open' | 'merged' = 'open'): PullRequestInfo => ({
number: pr.number,
title: pr.title,
htmlURL: pr.html_url,
baseBranch: pr.base.ref,
branch: pr.head.ref,
createdAt: moment(pr.created_at),
mergedAt: pr.merged_at ? moment(pr.merged_at) : undefined,
mergeCommitSha: pr.merge_commit_sha || '',
author: pr.user?.login || '',
repoName: pr.base.repo.full_name,
labels: attachSpeciaLabels(status, pr.labels?.map(lbl => lbl.name?.toLocaleLowerCase('en') || '') || []),
milestone: pr.milestone?.title || '',
body: pr.body || '',
assignees: pr.assignees?.map(asignee => asignee?.login || '') || [],
requestedReviewers: pr.requested_reviewers?.map(reviewer => reviewer?.login || '') || [],
approvedReviewers: [],
reviews: undefined,
status
})
const mapComment = (comment: Unpacked<PullReviewsData>): CommentInfo => ({
id: comment.id,
htmlURL: comment.html_url,
submittedAt: comment.submitted_at ? moment(comment.submitted_at) : undefined,
author: comment.user?.login || '',
body: comment.body,
state: comment.state
})
+4 -59
View File
@@ -1,12 +1,12 @@
import * as core from '@actions/core'
import * as github from '@actions/github'
import * as semver from 'semver'
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
import {SemVer} from 'semver'
import {RegexTransformer, TagResolver, Transformer} from './types'
import {createCommandManager} from './gitHelper'
import moment from 'moment'
import {validateTransformer} from './regexUtils'
import {BaseRepository} from '../repositories/BaseRepository'
export interface TagResult {
from: TagInfo | null
@@ -25,69 +25,14 @@ export interface SortableTagInfo extends TagInfo {
}
export class Tags {
constructor(private octokit: Octokit) {}
constructor(private repositoryUtils: BaseRepository) {}
async getTags(owner: string, repo: string, maxTagsToFetch: number): Promise<TagInfo[]> {
const tagsInfo: TagInfo[] = []
const options = this.octokit.repos.listTags.endpoint.merge({
owner,
repo,
direction: 'desc',
per_page: 100
})
for await (const response of this.octokit.paginate.iterator(options)) {
type TagsListData = RestEndpointMethodTypes['repos']['listTags']['response']['data']
const tags: TagsListData = response.data as TagsListData
for (const tag of tags) {
tagsInfo.push({
name: tag.name,
commit: tag.commit.sha
})
}
// for performance only fetch newest maxTagsToFetch tags!!
if (tagsInfo.length >= maxTagsToFetch) {
break
}
}
core.info(`️ Found ${tagsInfo.length} (fetching max: ${maxTagsToFetch}) tags from the GitHub API for ${owner}/${repo}`)
return tagsInfo
return this.repositoryUtils.getTags(owner, repo, maxTagsToFetch)
}
async fillTagInformation(repositoryPath: string, owner: string, repo: string, tagInfo: TagInfo): Promise<TagInfo> {
const options = this.octokit.repos.getReleaseByTag.endpoint.merge({
owner,
repo,
tag: tagInfo.name
})
try {
const response = await this.octokit.request(options)
type ReleaseInformation = RestEndpointMethodTypes['repos']['getReleaseByTag']['response']['data']
const release: ReleaseInformation = response.data as ReleaseInformation
tagInfo.date = moment(release.created_at)
core.info(`️ Retrieved information about the release associated with ${tagInfo.name} from the GitHub API`)
} catch (error) {
core.info(`⚠️ No release information found for ${tagInfo.name}, trying to retrieve tag creation time as fallback.`)
const gitHelper = await createCommandManager(repositoryPath)
const creationTimeString = await gitHelper.tagCreation(tagInfo.name)
const creationTime = moment(creationTimeString)
if (creationTimeString !== null && creationTime.isValid()) {
tagInfo.date = creationTime
core.info(
`️ Resolved tag creation time (${creationTimeString}) from 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}`
)
} else {
core.info(
`⚠️ Could not retrieve tag creation time via git cli 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}'`
)
}
}
return tagInfo
return this.repositoryUtils.fillTagInformation(repositoryPath, owner, repo, tagInfo)
}
async findPredecessorTag(
+1 -1
View File
@@ -1,5 +1,5 @@
import * as core from '@actions/core'
import {Rule, RegexTransformer} from './pr-collector/types'
import {RegexTransformer, Rule} from './pr-collector/types'
import {PullRequestInfo, retrieveProperty} from './pr-collector/pullRequests'
import {validateTransformer} from './pr-collector/regexUtils'
+9 -6
View File
@@ -1,13 +1,13 @@
import * as core from '@actions/core'
import {Configuration} from './configuration'
import {checkExportedData, writeCacheData} from './utils'
import {PullRequestData, buildChangelog} from './transform'
import {buildChangelog, PullRequestData} from './transform'
import {PullRequestCollector} from './pr-collector/prCollector'
import {failOrError} from './pr-collector/utils'
import {TagInfo} from './pr-collector/tags'
import {DiffInfo} from './pr-collector/commits'
import {PullRequestInfo} from './pr-collector/pullRequests'
import * as fs from 'fs'
import {BaseRepository} from './repositories/BaseRepository'
export interface ReleaseNotesOptions {
owner: string // the owner of the repository
@@ -21,6 +21,7 @@ export interface ReleaseNotesOptions {
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`
repositoryUtils: BaseRepository // the repository implementation used to generate the changelog
}
export interface Data {
@@ -32,7 +33,7 @@ export interface Data {
export class ReleaseNotesBuilder {
constructor(
private baseUrl: string | null,
private token: string | null,
private repositoryUtils: BaseRepository,
private repositoryPath: string,
private owner: string | null,
private repo: string | null,
@@ -78,7 +79,7 @@ export class ReleaseNotesBuilder {
const prData = await new PullRequestCollector(
this.baseUrl,
this.token,
this.repositoryUtils,
this.repositoryPath,
this.owner,
this.repo,
@@ -110,7 +111,8 @@ export class ReleaseNotesBuilder {
fetchReleaseInformation: this.fetchReleaseInformation,
fetchReviews: this.fetchReviews,
commitMode: this.commitMode,
configuration: this.configuration
configuration: this.configuration,
repositoryUtils: this.repositoryUtils
}
const mergedPullRequests = prData.mergedPullRequests
const diffInfo = prData.diffInfo
@@ -163,7 +165,8 @@ export class ReleaseNotesBuilder {
fetchReleaseInformation: this.fetchReleaseInformation || orgOptions.fetchReleaseInformation,
fetchReviews: this.fetchReviews || orgOptions.fetchReviews,
commitMode: this.commitMode || orgOptions.commitMode,
configuration: this.configuration || orgOptions.configuration
configuration: this.configuration || orgOptions.configuration,
repositoryUtils: this.repositoryUtils || orgOptions.repositoryUtils
}
this.setOutputs(options, diffInfo, mergedPullRequests)
+68
View File
@@ -0,0 +1,68 @@
import {TagInfo} from '../pr-collector/tags'
import {DiffInfo} from '../pr-collector/commits'
import moment from 'moment/moment'
import {PullRequestInfo} from '../pr-collector/pullRequests'
import * as core from '@actions/core'
import {createCommandManager} from '../pr-collector/gitHelper'
export abstract class BaseRepository {
proxy?: string
noProxyArray: string[]
// Define an abstract getter for the default URL
abstract get defaultUrl(): string
// Define the abstract getter for the home URL (also used for some replace patterns)
abstract get homeUrl(): string
protected constructor(
protected token: string,
protected url: string | undefined,
protected repositoryPath: string
) {
this.proxy = process.env.https_proxy || process.env.HTTPS_PROXY
const noProxy = process.env.no_proxy || process.env.NO_PROXY
this.noProxyArray = []
if (noProxy) {
this.noProxyArray = noProxy.split(',')
}
}
abstract getTags(owner: string, repo: string, maxTagsToFetch: number): Promise<TagInfo[]>
abstract fillTagInformation(repositoryPath: string, owner: string, repo: string, tagInfo: TagInfo): Promise<TagInfo>
abstract getDiffRemote(owner: string, repo: string, base: string, head: string): Promise<DiffInfo>
abstract getForCommitHash(owner: string, repo: string, commit_sha: string, maxPullRequests: number): Promise<PullRequestInfo[]>
abstract getBetweenDates(
owner: string,
repo: string,
fromDate: moment.Moment,
toDate: moment.Moment,
maxPullRequests: number
): Promise<PullRequestInfo[]>
abstract getOpen(owner: string, repo: string, maxPullRequests: number): Promise<PullRequestInfo[]>
abstract getReviews(owner: string, repo: string, pr: PullRequestInfo): Promise<void>
protected async getTagByCreateTime(repositoryPath: string, tagInfo: TagInfo): Promise<TagInfo> {
core.info(`⚠️ No release information found for ${tagInfo.name}, trying to retrieve tag creation time as fallback.`)
const gitHelper = await createCommandManager(repositoryPath)
const creationTimeString = await gitHelper.tagCreation(tagInfo.name)
const creationTime = moment(creationTimeString)
if (creationTimeString !== null && creationTime.isValid()) {
tagInfo.date = creationTime
core.info(
`️ Resolved tag creation time (${creationTimeString}) from 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}`
)
} else {
core.info(
`⚠️ Could not retrieve tag creation time via git cli 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}'`
)
}
return tagInfo
}
}
+249
View File
@@ -0,0 +1,249 @@
import {BaseRepository} from './BaseRepository'
import {TagInfo} from '../pr-collector/tags'
import {CommentInfo, PullRequestInfo} from '../pr-collector/pullRequests'
import {DiffInfo} from '../pr-collector/commits'
import {Api, PullRequest, PullReview, giteaApi} from 'gitea-js'
import moment from 'moment'
import * as core from '@actions/core'
import {createCommandManager} from '../pr-collector/gitHelper'
interface Pulls {
closed: PullRequest[]
open: PullRequest[]
}
export class GiteaRepository extends BaseRepository {
private api: Api<unknown>
get defaultUrl(): string {
return 'https://gitea.com'
}
get homeUrl(): string {
return 'https://gitea.com'
}
constructor(token: string, url: string | undefined, repositoryPath: string) {
super(token, url, repositoryPath)
this.url = url || this.defaultUrl
this.api = giteaApi(this.url, {
token
})
}
async fillTagInformation(repositoryPath: string, owner: string, repo: string, tagInfo: TagInfo): Promise<TagInfo> {
const response = await this.api.repos.repoGetTag(owner, repo, tagInfo.name)
if (response.error === null) {
if (response.data.commit) {
tagInfo.date = moment(response.data.commit.created)
core.info(`️ Retrieved information about the release associated with ${tagInfo.name} from the Gitea API`)
return tagInfo
}
}
return await this.getTagByCreateTime(repositoryPath, tagInfo)
}
async getBetweenDates(
owner: string,
repo: string,
fromDate: moment.Moment,
toDate: moment.Moment,
maxPullRequests: number
): Promise<PullRequestInfo[]> {
const mergedPRs: PullRequestInfo[] = []
await this.getAllPullRequest(owner, repo, 'closed', maxPullRequests)
for (const pr of GiteaRepository.pulls.closed.filter(p => !!p.merged_at)) {
if (moment(pr.closed_at) > fromDate && moment(pr.closed_at) < toDate) {
mergedPRs.push(this.mapPullRequest(pr, 'merged'))
}
}
return mergedPRs
}
private mapPullRequest(pr: PullRequest, status: 'open' | 'merged' = 'open'): PullRequestInfo {
return {
number: pr.number || 0,
title: pr.title || '',
htmlURL: pr.html_url || '',
baseBranch: pr.base?.repo?.default_branch || '',
branch: pr.merge_base || '',
mergedAt: pr.merged_at ? moment(pr.merged_at) : undefined,
mergeCommitSha: pr.merge_commit_sha || '',
author: pr.user?.login || '',
repoName: pr.base?.repo?.full_name || '',
labels: pr.labels?.map(label => label.name) as string[],
milestone: pr.milestone?.title || '',
body: pr.body || '',
assignees: pr.assignees?.map(user => user.full_name) as string[],
requestedReviewers: pr.requested_reviewers?.map(user => user.full_name) as string[],
approvedReviewers: [],
createdAt: moment(pr.created_at),
status,
reviews: undefined
}
}
/**
* WARNING: This does not actually get the diff from the remote, as Gitea does not offer a compareable API.
* This uses the local repository to get the diff. NOTE: As such, gitea integration requires the repo available.
*/
async getDiffRemote(owner: string, repo: string, base: string, head: string): Promise<DiffInfo> {
let changedFilesCount = 0
let additionCount = 0
let deletionCount = 0
const changeCount = 0
let commitCount = 0
const gitHelper = await createCommandManager(this.repositoryPath)
// Get the diff stats between the two branches/commits
const diffStat = await gitHelper.execGit(['diff', '--stat', `${base}...${head}`])
const diffStatLines = diffStat.stdout.split('\n')
for (const line of diffStatLines) {
// Extract the addition and deletion counts from each line of the git diff output
const match = line.match(/(\d+) insertions?\(\+\), (\d+) deletions?\(-\)/)
if (match) {
additionCount += parseInt(match[1], 10)
deletionCount += parseInt(match[2], 10)
}
}
// Get the list of changed files
const diffNameOnly = await gitHelper.execGit(['diff', '--name-only', `${base}...${head}`])
const changedFiles = diffNameOnly.stdout.split('\n')
changedFilesCount = changedFiles.length - 1 // Subtract one for the empty line at the end
// Get the commit count between the two branches/commits
const logCount = await gitHelper.execGit(['rev-list', '--count', `${base}...${head}`])
commitCount = parseInt(logCount.stdout.trim(), 10)
// Now let's get the commit logs between the two branches/commits
const log = await gitHelper.execGit(['log', '--pretty=format:%H||||%an||||%ae||||%ad||||%cn||||%ce||||%cd||||%s', `${base}...${head}`])
const commitLogs = log.stdout.trim().split('\n')
// Process commit logs
const commitInfo = commitLogs.map(commitLog => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [sha, authorName, authorEmail, authorDate, committerName, committerEmail, committerDate, subject] = commitLog.split('||||')
return {
sha,
summary: subject,
message: '', // This would require another git command to get the full message if needed
author: authorName,
authorDate: moment(authorDate, 'ddd MMM DD HH:mm:ss YYYY ZZ', false),
committer: committerName,
commitDate: moment(committerDate, 'ddd MMM DD HH:mm:ss YYYY ZZ', false),
prNumber: undefined // This is not available directly from git, would require additional logic to associate commits with PRs
}
})
return {
changedFiles: changedFilesCount,
additions: additionCount,
deletions: deletionCount,
changes: changeCount,
commits: commitCount,
commitInfo
}
}
static pulls: Pulls = {
closed: [],
open: []
}
private async getAllPullRequest(owner: string, repo: string, state: 'closed' | 'open', maxPullRequests: number): Promise<void> {
if (GiteaRepository.pulls[state].length === 0) {
let page = 1
let count = 0
while (count < maxPullRequests) {
const limit = Math.min(50, maxPullRequests)
const response = await this.api.repos.repoListPullRequests(owner, repo, {
sort: 'recentupdate',
state,
limit,
page
})
if (response.error === null) {
GiteaRepository.pulls[state].push(...response.data)
} else {
core.error(`️ Some errors. ${response.error.message}`)
}
page++
count += response.data.length
if (response.data.length === 0) break
}
}
}
async getForCommitHash(owner: string, repo: string, commit_sha: string, maxPullRequests: number): Promise<PullRequestInfo[]> {
const mergedPRs: PullRequestInfo[] = []
await this.getAllPullRequest(owner, repo, 'closed', maxPullRequests)
for (const pr of GiteaRepository.pulls.closed) {
if (pr.merge_commit_sha === commit_sha) {
mergedPRs.push(this.mapPullRequest(pr, pr.merged_at ? 'merged' : 'open'))
}
}
core.debug(`Completed fetching PRs from API. Fetched: ${mergedPRs.length}`)
return mergedPRs
}
async getOpen(owner: string, repo: string, maxPullRequests: number): Promise<PullRequestInfo[]> {
await this.getAllPullRequest(owner, repo, 'open', maxPullRequests)
const openPrs: PullRequestInfo[] = []
for (const pr of GiteaRepository.pulls.open) {
openPrs.push(this.mapPullRequest(pr, 'open'))
}
return openPrs
}
async getReviews(owner: string, repo: string, pr: PullRequestInfo): Promise<void> {
const prReviews: CommentInfo[] = []
const response = await this.api.repos.repoListPullReviews(owner, repo, pr.number, {})
if (response.error === null) {
for (const comment of response.data) {
prReviews.push(this.mapComment(comment))
}
} else {
core.error(`️ Some errors. ${response.error.message}`)
}
pr.reviews = prReviews
}
private mapComment = (comment: PullReview): CommentInfo => ({
id: comment.id || 0,
htmlURL: comment.html_url || '',
submittedAt: comment.submitted_at ? moment(comment.submitted_at) : undefined,
author: comment.user?.login || '',
body: comment.body || '',
state: comment.state
})
async getTags(owner: string, repo: string, maxTagsToFetch: number): Promise<TagInfo[]> {
core.debug(`Start to get tag from gitea`)
const response = await this.api.repos.repoListTags(owner, repo, {
limit: maxTagsToFetch
})
const tagsInfo: TagInfo[] = []
if (response.error === null) {
for (const tag of response.data) {
tagsInfo.push({
name: tag.name || '',
commit: tag.commit?.sha
})
}
} else {
core.error(`️ Some errors. ${response.error.message}`)
}
core.info(`️ Found ${tagsInfo.length} (fetching max: ${maxTagsToFetch}) tags from the GitHub API for ${owner}/${repo}`)
return tagsInfo
}
}
+305
View File
@@ -0,0 +1,305 @@
import {BaseRepository} from './BaseRepository'
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
import {HttpsProxyAgent} from 'https-proxy-agent'
import * as core from '@actions/core'
import {TagInfo} from '../pr-collector/tags'
import moment from 'moment/moment'
import {DiffInfo} from '../pr-collector/commits'
import {CommentInfo, PullData, PullRequestInfo, PullReviewsData, PullsListData} from '../pr-collector/pullRequests'
import {Unpacked} from '../pr-collector/utils'
export class GithubRepository extends BaseRepository {
async getDiffRemote(owner: string, repo: string, base: string, head: string): Promise<DiffInfo> {
let changedFilesCount = 0
let additionCount = 0
let deletionCount = 0
let changeCount = 0
let commitCount = 0
// Fetch comparisons recursively until we don't find any commits
// This is because the GitHub API limits the number of commits returned in a single response.
let commits: RestEndpointMethodTypes['repos']['compareCommits']['response']['data']['commits'] = []
let compareHead = head
// eslint-disable-next-line no-constant-condition
while (true) {
const compareResult = await this.octokit.repos.compareCommits({
owner,
repo,
base,
head: compareHead
})
if (compareResult.data.total_commits === 0) {
break
}
changedFilesCount += compareResult.data.files?.length ?? 0
const files = compareResult.data.files
if (files !== undefined) {
for (const file of files) {
additionCount += file.additions
deletionCount += file.deletions
changeCount += file.changes
}
}
commitCount += compareResult.data.commits.length
commits = compareResult.data.commits.concat(commits)
compareHead = `${commits[0].sha}^`
}
core.info(`️ Found ${commits.length} commits from the GitHub API for ${owner}/${repo}`)
return {
changedFiles: changedFilesCount,
additions: additionCount,
deletions: deletionCount,
changes: changeCount,
commits: commitCount,
commitInfo: commits
.filter(commit => commit.sha)
.map(commit => ({
sha: commit.sha || '',
summary: commit.commit.message.split('\n')[0],
message: commit.commit.message,
author: commit.author?.login || '',
authorDate: moment(commit.commit.author?.date),
committer: commit.committer?.login || '',
commitDate: moment(commit.commit.committer?.date),
prNumber: undefined
}))
}
}
async getForCommitHash(owner: string, repo: string, commit_sha: string, maxPullRequests: number): Promise<PullRequestInfo[]> {
const mergedPRs: PullRequestInfo[] = []
const options = this.octokit.repos.listPullRequestsAssociatedWithCommit.endpoint.merge({
owner,
repo,
commit_sha,
per_page: `${Math.min(10, maxPullRequests)}`,
direction: 'desc'
})
for await (const response of this.octokit.paginate.iterator(options)) {
const prs: PullsListData = response.data as PullsListData
for (const pr of prs) {
mergedPRs.push(this.mapPullRequest(pr, pr.merged_at ? 'merged' : 'open'))
}
}
return mergedPRs
}
async getBetweenDates(
owner: string,
repo: string,
fromDate: moment.Moment,
toDate: moment.Moment,
maxPullRequests: number
): Promise<PullRequestInfo[]> {
const mergedPRs: PullRequestInfo[] = []
const options = this.octokit.pulls.list.endpoint.merge({
owner,
repo,
state: 'closed',
sort: 'merged',
per_page: `${Math.min(100, maxPullRequests)}`,
direction: 'desc'
})
for await (const response of this.octokit.paginate.iterator(options)) {
const prs: PullsListData = response.data as PullsListData
for (const pr of prs.filter(p => !!p.merged_at)) {
mergedPRs.push(this.mapPullRequest(pr, 'merged'))
}
if (mergedPRs.length >= maxPullRequests) {
core.warning(`⚠️ Reached 'maxPullRequests' count ${maxPullRequests} (1)`)
break // bail out early to not keep iterating forever
} else if (prs.length > 0) {
if (this.fetchedEnough(prs, fromDate)) {
return mergedPRs // bail out early to not keep iterating on PRs super old
}
} else {
core.debug(`⚠️ No more PRs retrieved from API. Fetched so far: ${mergedPRs.length}`)
break
}
}
return mergedPRs
}
async getOpen(owner: string, repo: string, maxPullRequests: number): Promise<PullRequestInfo[]> {
const openPrs: PullRequestInfo[] = []
const options = this.octokit.pulls.list.endpoint.merge({
owner,
repo,
state: 'open',
sort: 'created',
per_page: '100',
direction: 'desc'
})
for await (const response of this.octokit.paginate.iterator(options)) {
const prs: PullsListData = response.data as PullsListData
for (const pr of prs) {
openPrs.push(this.mapPullRequest(pr, 'open'))
}
const firstPR = prs[0]
if (firstPR === undefined || openPrs.length >= maxPullRequests) {
if (openPrs.length >= maxPullRequests) {
core.warning(`⚠️ Reached 'maxPullRequests' count ${maxPullRequests} (2)`)
}
break // bail out early to not keep iterating forever
}
}
return openPrs
}
async getReviews(owner: string, repo: string, pr: PullRequestInfo): Promise<void> {
const options = this.octokit.pulls.listReviews.endpoint.merge({
owner,
repo,
pull_number: pr.number,
sort: 'created',
direction: 'desc'
})
const prReviews: CommentInfo[] = []
for await (const response of this.octokit.paginate.iterator(options)) {
const comments: PullReviewsData = response.data as PullReviewsData
for (const comment of comments) {
prReviews.push(this.mapComment(comment))
}
}
pr.reviews = prReviews
}
get defaultUrl(): string {
return 'https://api.github.com'
}
get homeUrl(): string {
return this.url?.replace('api.', '') || 'https://github.com'
}
private octokit: Octokit
constructor(token: string, url: string | undefined, repositoryPath: string) {
super(token, url, repositoryPath)
this.url = url || this.defaultUrl
// load octokit instance
this.octokit = new Octokit({
auth: `token ${this.token}`,
baseUrl: this.url
})
if (this.proxy) {
const agent = new HttpsProxyAgent(this.proxy)
this.octokit.hook.before('request', options => {
if (this.noProxyArray.includes(options.request.hostname)) {
return
}
options.request.agent = agent
})
}
}
async getTags(owner: string, repo: string, maxTagsToFetch: number): Promise<TagInfo[]> {
const tagsInfo: TagInfo[] = []
const options = this.octokit.repos.listTags.endpoint.merge({
owner,
repo,
direction: 'desc',
per_page: 100
})
for await (const response of this.octokit.paginate.iterator(options)) {
type TagsListData = RestEndpointMethodTypes['repos']['listTags']['response']['data']
const tags: TagsListData = response.data as TagsListData
for (const tag of tags) {
tagsInfo.push({
name: tag.name,
commit: tag.commit.sha
})
}
// for performance only fetch newest maxTagsToFetch tags!!
if (tagsInfo.length >= maxTagsToFetch) {
break
}
}
core.info(`️ Found ${tagsInfo.length} (fetching max: ${maxTagsToFetch}) tags from the GitHub API for ${owner}/${repo}`)
return tagsInfo
}
async fillTagInformation(repositoryPath: string, owner: string, repo: string, tagInfo: TagInfo): Promise<TagInfo> {
const options = this.octokit.repos.getReleaseByTag.endpoint.merge({
owner,
repo,
tag: tagInfo.name
})
try {
const response = await this.octokit.request(options)
type ReleaseInformation = RestEndpointMethodTypes['repos']['getReleaseByTag']['response']['data']
const release: ReleaseInformation = response.data as ReleaseInformation
tagInfo.date = moment(release.created_at)
core.info(`️ Retrieved information about the release associated with ${tagInfo.name} from the GitHub API`)
} catch (error) {
tagInfo = await this.getTagByCreateTime(repositoryPath, tagInfo)
}
return tagInfo
}
// helper function to add a special open label to prs not merged.
private attachSpecialLabels(status: 'open' | 'merged', labels: string[]): string[] {
labels.push(`--rcba-${status}`)
return labels
}
private mapPullRequest = (pr: PullData | Unpacked<PullsListData>, status: 'open' | 'merged' = 'open'): PullRequestInfo => ({
number: pr.number,
title: pr.title,
htmlURL: pr.html_url,
baseBranch: pr.base.ref,
branch: pr.head.ref,
createdAt: moment(pr.created_at),
mergedAt: pr.merged_at ? moment(pr.merged_at) : undefined,
mergeCommitSha: pr.merge_commit_sha || '',
author: pr.user?.login || '',
repoName: pr.base.repo.full_name,
labels: this.attachSpecialLabels(status, pr.labels?.map(lbl => lbl.name?.toLocaleLowerCase('en') || '') || []),
milestone: pr.milestone?.title || '',
body: pr.body || '',
assignees: pr.assignees?.map(asignee => asignee?.login || '') || [],
requestedReviewers: pr.requested_reviewers?.map(reviewer => reviewer?.login || '') || [],
approvedReviewers: [],
reviews: undefined,
status
})
private mapComment = (comment: Unpacked<PullReviewsData>): CommentInfo => ({
id: comment.id,
htmlURL: comment.html_url,
submittedAt: comment.submitted_at ? moment(comment.submitted_at) : undefined,
author: comment.user?.login || '',
body: comment.body,
state: comment.state
})
private fetchedEnough(pullRequests: PullsListData, fromDate: moment.Moment): boolean {
for (let i = 0; i < Math.min(pullRequests.length, 3); i++) {
const firstPR = pullRequests[i]
if (!firstPR.merged_at) {
// no merged_at timestamp -> look for the next
} else if (fromDate.isAfter(moment(firstPR.merged_at))) {
return true
} else {
break // not enough PRs yet, go further
}
}
return false
}
}
+2 -2
View File
@@ -11,7 +11,7 @@ import {
} from './pr-collector/pullRequests'
import {DiffInfo} from './pr-collector/commits'
import {validateTransformer} from './pr-collector/regexUtils'
import {Transformer, RegexTransformer} from './pr-collector/types'
import {RegexTransformer, Transformer} from './pr-collector/types'
import {ReleaseNotesOptions} from './releaseNotesBuilder'
import {matchesRules} from './regexUtils'
@@ -388,7 +388,7 @@ function fillAdditionalPlaceholders(
}
placeholderMap.set(
'RELEASE_DIFF',
`https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag.name}...${options.toTag.name}`
`${options.repositoryUtils.homeUrl}/${options.owner}/${options.repo}/compare/${options.fromTag.name}...${options.toTag.name}`
)
}
+10 -1
View File
@@ -7,6 +7,7 @@ import {DiffInfo} from './pr-collector/commits'
import {PullRequestInfo} from './pr-collector/pullRequests'
import {Data, ReleaseNotesOptions} from './releaseNotesBuilder'
import {env} from 'process'
/**
* Resolves the repository path, relatively to the GITHUB_WORKSPACE
*/
@@ -40,13 +41,21 @@ export function writeCacheData(data: Data, cacheOutput: string | null): void {
}
try {
fs.writeFileSync(cacheFile, JSON.stringify(data))
// use replacer to not cache the repositoryUtils (as that would contain token information)
fs.writeFileSync(cacheFile, JSON.stringify(data, replacer))
core.setOutput(`cache`, cacheFile)
} catch (error) {
core.warning(`Failed to write cache file. (${error})`)
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function replacer(key: string, value: any): any {
if (key === 'repositoryUtils') return undefined
if (key === 'token') return undefined
else return value
}
/**
* Retrieves the exported information from a previous run of the `release-changelog-builder-action`.
* If available, return a [ReleaseNotesData].
+2 -2
View File
@@ -7,7 +7,7 @@
"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` */
"lib": [ "ES2021.String", "dom"] /* Enable custom `ES2021.String` extension in typescript for `replaceAll` */
},
"exclude": ["node_modules", "**/*.test.ts", "pr-collector"]
"exclude": ["node_modules", "**/*.test.ts", "**/**/*.test.ts", "src/pr-collector"],
}