Merge pull request #1308 from mikepenz/feature/nested_categories
Introduce nested categorisation
This commit is contained in:
@@ -518,7 +518,7 @@ Regex replace pattern
|
|||||||
"source": "TITLE",
|
"source": "TITLE",
|
||||||
"transformer": {
|
"transformer": {
|
||||||
"pattern": "\\s*\\[([A-Z].{2,4}-.{2,5})\\][\\S\\s]*",
|
"pattern": "\\s*\\[([A-Z].{2,4}-.{2,5})\\][\\S\\s]*",
|
||||||
"target": ", [$1](https://corp.ticket-system.com/browse/$1)"
|
"target": "- [$1](https://corp.ticket-system.com/browse/$1)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import {clear} from '../src/transform'
|
||||||
import {mergeConfiguration, parseConfiguration, resolveConfiguration} from '../src/utils'
|
import {mergeConfiguration, parseConfiguration, resolveConfiguration} from '../src/utils'
|
||||||
|
|
||||||
jest.setTimeout(180000)
|
jest.setTimeout(180000)
|
||||||
|
clear()
|
||||||
|
|
||||||
it('Configurations are merged correctly', async () => {
|
it('Configurations are merged correctly', async () => {
|
||||||
const configurationJson = parseConfiguration(`{
|
const configurationJson = parseConfiguration(`{
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import {mergeConfiguration, resolveConfiguration} from '../../src/utils'
|
import {mergeConfiguration, resolveConfiguration} from '../../src/utils'
|
||||||
import {ReleaseNotesBuilder} from '../../src/releaseNotesBuilder'
|
import {ReleaseNotesBuilder} from '../../src/releaseNotesBuilder'
|
||||||
import {GiteaRepository} from '../../src/repositories/GiteaRepository'
|
import {GiteaRepository} from '../../src/repositories/GiteaRepository'
|
||||||
|
import {clear} from '../../src/transform'
|
||||||
|
|
||||||
jest.setTimeout(180000)
|
jest.setTimeout(180000)
|
||||||
|
clear()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Before starting testing, you should manually clone the repository
|
* Before starting testing, you should manually clone the repository
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ import {checkExportedData, mergeConfiguration, resolveConfiguration} from '../..
|
|||||||
import {buildChangelog} from '../../src/transform'
|
import {buildChangelog} from '../../src/transform'
|
||||||
import {pullData} from '../../src/pr-collector/prCollector'
|
import {pullData} from '../../src/pr-collector/prCollector'
|
||||||
import {GiteaRepository} from '../../src/repositories/GiteaRepository'
|
import {GiteaRepository} from '../../src/repositories/GiteaRepository'
|
||||||
|
import {clear} from '../../src/transform'
|
||||||
|
|
||||||
jest.setTimeout(180000)
|
jest.setTimeout(180000)
|
||||||
|
clear()
|
||||||
|
|
||||||
// load octokit instance
|
// load octokit instance
|
||||||
const enablePullData = false
|
const enablePullData = false
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ import * as path from 'path'
|
|||||||
import * as process from 'process'
|
import * as process from 'process'
|
||||||
import * as cp from 'child_process'
|
import * as cp from 'child_process'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
|
import {clear} from '../src/transform'
|
||||||
|
|
||||||
jest.setTimeout(180000)
|
jest.setTimeout(180000)
|
||||||
|
clear()
|
||||||
|
|
||||||
test('missing values should result in failure', () => {
|
test('missing values should result in failure', () => {
|
||||||
expect.assertions(1)
|
expect.assertions(1)
|
||||||
|
|||||||
@@ -1,27 +1,29 @@
|
|||||||
import { transformStringToValue, validateRegex } from '../src/pr-collector/regexUtils'
|
import {transformStringToValue, validateRegex} from '../src/pr-collector/regexUtils'
|
||||||
import { Regex } from '../src/pr-collector/types'
|
import {Regex} from '../src/pr-collector/types'
|
||||||
|
import {clear} from '../src/transform'
|
||||||
|
|
||||||
jest.setTimeout(180000)
|
jest.setTimeout(180000)
|
||||||
|
clear()
|
||||||
|
|
||||||
it('Replace into target', async () => {
|
it('Replace into target', async () => {
|
||||||
const regex: Regex = {
|
const regex: Regex = {
|
||||||
pattern: '.*(\\[Feature\\]|\\[Issue\\]).*',
|
pattern: '.*(\\[Feature\\]|\\[Issue\\]).*',
|
||||||
target: '$1',
|
target: '$1'
|
||||||
}
|
}
|
||||||
const validatedRegex = validateRegex(regex)
|
const validatedRegex = validateRegex(regex)
|
||||||
expect(validateRegex).not.toBeNull()
|
expect(validateRegex).not.toBeNull()
|
||||||
expect(transformStringToValue("[Feature] TEST", validatedRegex!!)).toStrictEqual(`[Feature]`)
|
expect(transformStringToValue('[Feature] TEST', validatedRegex!!)).toStrictEqual(`[Feature]`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Replace all into target', async () => {
|
it('Replace all into target', async () => {
|
||||||
const regex: Regex = {
|
const regex: Regex = {
|
||||||
pattern: '.*(\\[Feature\\]|\\[Issue\\]).*',
|
pattern: '.*(\\[Feature\\]|\\[Issue\\]).*',
|
||||||
method: 'replaceAll',
|
method: 'replaceAll',
|
||||||
target: '$1',
|
target: '$1'
|
||||||
}
|
}
|
||||||
const validatedRegex = validateRegex(regex)
|
const validatedRegex = validateRegex(regex)
|
||||||
expect(validateRegex).not.toBeNull()
|
expect(validateRegex).not.toBeNull()
|
||||||
expect(transformStringToValue("[Feature] TEST", validatedRegex!!)).toStrictEqual(`[Feature]`)
|
expect(transformStringToValue('[Feature] TEST', validatedRegex!!)).toStrictEqual(`[Feature]`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Match without target', async () => {
|
it('Match without target', async () => {
|
||||||
@@ -31,27 +33,27 @@ it('Match without target', async () => {
|
|||||||
}
|
}
|
||||||
const validatedRegex = validateRegex(regex)
|
const validatedRegex = validateRegex(regex)
|
||||||
expect(validateRegex).not.toBeNull()
|
expect(validateRegex).not.toBeNull()
|
||||||
expect(transformStringToValue("[Feature] TEST", validatedRegex!!)).toStrictEqual(`[Feature]`)
|
expect(transformStringToValue('[Feature] TEST', validatedRegex!!)).toStrictEqual(`[Feature]`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Match into target', async () => {
|
it('Match into target', async () => {
|
||||||
const regex: Regex = {
|
const regex: Regex = {
|
||||||
pattern: '(?<label>\\[Feature\\]|\\[Issue\\])',
|
pattern: '(?<label>\\[Feature\\]|\\[Issue\\])',
|
||||||
method: 'match',
|
method: 'match',
|
||||||
target: '$1',
|
target: '$1'
|
||||||
}
|
}
|
||||||
const validatedRegex = validateRegex(regex)
|
const validatedRegex = validateRegex(regex)
|
||||||
expect(validateRegex).not.toBeNull()
|
expect(validateRegex).not.toBeNull()
|
||||||
expect(transformStringToValue("[Feature] TEST", validatedRegex!!)).toStrictEqual(`[Feature]`)
|
expect(transformStringToValue('[Feature] TEST', validatedRegex!!)).toStrictEqual(`[Feature]`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Match into named group', async () => {
|
it('Match into named group', async () => {
|
||||||
const regex: Regex = {
|
const regex: Regex = {
|
||||||
pattern: '(?<label>\\[Feature\\]|\\[Issue\\])',
|
pattern: '(?<label>\\[Feature\\]|\\[Issue\\])',
|
||||||
method: 'match',
|
method: 'match',
|
||||||
target: 'label',
|
target: 'label'
|
||||||
}
|
}
|
||||||
const validatedRegex = validateRegex(regex)
|
const validatedRegex = validateRegex(regex)
|
||||||
expect(validateRegex).not.toBeNull()
|
expect(validateRegex).not.toBeNull()
|
||||||
expect(transformStringToValue("[Feature] TEST", validatedRegex!!)).toStrictEqual(`[Feature]`)
|
expect(transformStringToValue('[Feature] TEST', validatedRegex!!)).toStrictEqual(`[Feature]`)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import {mergeConfiguration, resolveConfiguration} from '../src/utils'
|
import {mergeConfiguration, resolveConfiguration} from '../src/utils'
|
||||||
import {ReleaseNotesBuilder} from '../src/releaseNotesBuilder'
|
import {ReleaseNotesBuilder} from '../src/releaseNotesBuilder'
|
||||||
import {GithubRepository} from '../src/repositories/GithubRepository'
|
import {GithubRepository} from '../src/repositories/GithubRepository'
|
||||||
|
import {clear} from '../src/transform'
|
||||||
|
|
||||||
jest.setTimeout(180000)
|
jest.setTimeout(180000)
|
||||||
|
clear()
|
||||||
|
|
||||||
const token = process.env.GITHUB_TOKEN || ''
|
const token = process.env.GITHUB_TOKEN || ''
|
||||||
const githubRepository = new GithubRepository(token, undefined, '.')
|
const githubRepository = new GithubRepository(token, undefined, '.')
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ import {checkExportedData, mergeConfiguration, resolveConfiguration} from '../sr
|
|||||||
import {buildChangelog} from '../src/transform'
|
import {buildChangelog} from '../src/transform'
|
||||||
import {pullData} from '../src/pr-collector/prCollector'
|
import {pullData} from '../src/pr-collector/prCollector'
|
||||||
import {GithubRepository} from '../src/repositories/GithubRepository'
|
import {GithubRepository} from '../src/repositories/GithubRepository'
|
||||||
|
import {clear} from '../src/transform'
|
||||||
|
|
||||||
jest.setTimeout(180000)
|
jest.setTimeout(180000)
|
||||||
|
clear()
|
||||||
|
|
||||||
// load octokit instance
|
// load octokit instance
|
||||||
const enablePullData = false // if false -> use cache for data
|
const enablePullData = false // if false -> use cache for data
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { TagResolver } from '../src/configuration'
|
import {TagResolver} from '../src/configuration'
|
||||||
import { validateRegex } from '../src/pr-collector/regexUtils'
|
import {validateRegex} from '../src/pr-collector/regexUtils'
|
||||||
import {filterTags, prepareAndSortTags, TagInfo, transformTags} from '../src/pr-collector/tags'
|
import {filterTags, prepareAndSortTags, TagInfo, transformTags} from '../src/pr-collector/tags'
|
||||||
|
import {clear} from '../src/transform'
|
||||||
|
|
||||||
jest.setTimeout(180000)
|
jest.setTimeout(180000)
|
||||||
|
clear()
|
||||||
|
|
||||||
it('Should order tags correctly using semver', async () => {
|
it('Should order tags correctly using semver', async () => {
|
||||||
const tags: TagInfo[] = [
|
const tags: TagInfo[] = [
|
||||||
@@ -152,7 +154,6 @@ it('Should filter tags correctly using the regex (inverse)', async () => {
|
|||||||
expect(filtered).toStrictEqual(`0.1.0-b01,1.0.0,1.0.0-a01,2.0.0,10.1.0,20.0.2`)
|
expect(filtered).toStrictEqual(`0.1.0-b01,1.0.0,1.0.0-a01,2.0.0,10.1.0,20.0.2`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
it('Should transform tags correctly using the regex', async () => {
|
it('Should transform tags correctly using the regex', async () => {
|
||||||
const tags: TagInfo[] = [
|
const tags: TagInfo[] = [
|
||||||
{name: 'api-0.0.1', commit: ''},
|
{name: 'api-0.0.1', commit: ''},
|
||||||
@@ -168,13 +169,13 @@ it('Should transform tags correctly using the regex', async () => {
|
|||||||
const tagResolver: TagResolver = {
|
const tagResolver: TagResolver = {
|
||||||
method: 'non-existing-method',
|
method: 'non-existing-method',
|
||||||
transformer: {
|
transformer: {
|
||||||
pattern: '(api\-)?(.+)',
|
pattern: '(api-)?(.+)',
|
||||||
target: "$2"
|
target: '$2'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const transformer = validateRegex(tagResolver.transformer)
|
const transformer = validateRegex(tagResolver.transformer)
|
||||||
if(transformer != null) {
|
if (transformer != null) {
|
||||||
const transformed = transformTags(tags, transformer)
|
const transformed = transformTags(tags, transformer)
|
||||||
.map(function (tag) {
|
.map(function (tag) {
|
||||||
return tag.name
|
return tag.name
|
||||||
|
|||||||
+22
-34
@@ -4,8 +4,11 @@ import {Configuration, DefaultConfiguration} from '../src/configuration'
|
|||||||
import {PullRequestInfo} from '../src/pr-collector/pullRequests'
|
import {PullRequestInfo} from '../src/pr-collector/pullRequests'
|
||||||
import {DefaultDiffInfo} from '../src/pr-collector/commits'
|
import {DefaultDiffInfo} from '../src/pr-collector/commits'
|
||||||
import {GithubRepository} from '../src/repositories/GithubRepository'
|
import {GithubRepository} from '../src/repositories/GithubRepository'
|
||||||
|
import {clear} from '../src/transform'
|
||||||
|
import {buildChangelogTest} from './utils'
|
||||||
|
|
||||||
jest.setTimeout(180000)
|
jest.setTimeout(180000)
|
||||||
|
clear()
|
||||||
|
|
||||||
const configuration = Object.assign({}, DefaultConfiguration)
|
const configuration = Object.assign({}, DefaultConfiguration)
|
||||||
configuration.categories = [
|
configuration.categories = [
|
||||||
@@ -150,7 +153,7 @@ it('Extract label from title, combined regex', async () => {
|
|||||||
on_property: 'title'
|
on_property: 'title'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
expect(buildChangelogTest(configuration, mergedPullRequests)).toStrictEqual(
|
expect(buildChangelogTest(configuration, mergedPullRequests, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features\n\n- [Feature][AB-1234] - this is a PR 1 title message\n - PR: #1\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Fixes\n\n- [Issue][AB-4321] - this is a PR 2 title message\n - PR: #2\n\n`
|
`## 🚀 Features\n\n- [Feature][AB-1234] - this is a PR 1 title message\n - PR: #1\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Fixes\n\n- [Issue][AB-4321] - this is a PR 2 title message\n - PR: #2\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -166,7 +169,7 @@ it('Extract label from title and body, combined regex', async () => {
|
|||||||
|
|
||||||
let prs = Array.from(mergedPullRequests)
|
let prs = Array.from(mergedPullRequests)
|
||||||
prs.push(pullRequestWithLabelInBody)
|
prs.push(pullRequestWithLabelInBody)
|
||||||
expect(buildChangelogTest(configuration, prs)).toStrictEqual(
|
expect(buildChangelogTest(configuration, prs, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features\n\n- [Feature][AB-1234] - this is a PR 1 title message\n - PR: #1\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n- label in body\n - PR: #5\n\n## 🐛 Fixes\n\n- [Issue][AB-4321] - this is a PR 2 title message\n - PR: #2\n\n`
|
`## 🚀 Features\n\n- [Feature][AB-1234] - this is a PR 1 title message\n - PR: #1\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n- label in body\n - PR: #5\n\n## 🐛 Fixes\n\n- [Issue][AB-4321] - this is a PR 2 title message\n - PR: #2\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -184,7 +187,7 @@ it('Extract label from title, split regex', async () => {
|
|||||||
on_property: 'title'
|
on_property: 'title'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
expect(buildChangelogTest(configuration, mergedPullRequests)).toStrictEqual(
|
expect(buildChangelogTest(configuration, mergedPullRequests, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features\n\n- [Feature][AB-1234] - this is a PR 1 title message\n - PR: #1\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Fixes\n\n- [Issue][AB-4321] - this is a PR 2 title message\n - PR: #2\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n`
|
`## 🚀 Features\n\n- [Feature][AB-1234] - this is a PR 1 title message\n - PR: #1\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Fixes\n\n- [Issue][AB-4321] - this is a PR 2 title message\n - PR: #2\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -202,7 +205,7 @@ it('Extract label from title, match', async () => {
|
|||||||
method: 'match'
|
method: 'match'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
expect(buildChangelogTest(configuration, mergedPullRequests)).toStrictEqual(
|
expect(buildChangelogTest(configuration, mergedPullRequests, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features\n\n- [Feature][AB-1234] - this is a PR 1 title message\n - PR: #1\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Fixes\n\n- [Issue][AB-4321] - this is a PR 2 title message\n - PR: #2\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n`
|
`## 🚀 Features\n\n- [Feature][AB-1234] - this is a PR 1 title message\n - PR: #1\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Fixes\n\n- [Issue][AB-4321] - this is a PR 2 title message\n - PR: #2\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -215,7 +218,7 @@ it('Extract label from title, match multiple', async () => {
|
|||||||
method: 'match'
|
method: 'match'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
expect(buildChangelogTest(configuration, mergedPullRequests)).toStrictEqual(
|
expect(buildChangelogTest(configuration, mergedPullRequests, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features\n\n- [Feature][AB-1234] - this is a PR 1 title message\n - PR: #1\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Fixes\n\n- [Issue][AB-4321] - this is a PR 2 title message\n - PR: #2\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n`
|
`## 🚀 Features\n\n- [Feature][AB-1234] - this is a PR 1 title message\n - PR: #1\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Fixes\n\n- [Issue][AB-4321] - this is a PR 2 title message\n - PR: #2\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -229,7 +232,7 @@ it('Extract label from title, match multiple, custon non matching label', async
|
|||||||
on_empty: '[Other]'
|
on_empty: '[Other]'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
expect(buildChangelogTest(configuration, mergedPullRequests)).toStrictEqual(
|
expect(buildChangelogTest(configuration, mergedPullRequests, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features\n\n- [Feature][AB-1234] - this is a PR 1 title message\n - PR: #1\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Fixes\n\n- [Issue][AB-4321] - this is a PR 2 title message\n - PR: #2\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n## 🧪 Others\n\n- [AB-404] - not found label\n - PR: #4\n\n`
|
`## 🚀 Features\n\n- [Feature][AB-1234] - this is a PR 1 title message\n - PR: #1\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Fixes\n\n- [Issue][AB-4321] - this is a PR 2 title message\n - PR: #2\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n## 🧪 Others\n\n- [AB-404] - not found label\n - PR: #4\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -370,7 +373,7 @@ it('Match multiple labels exhaustive for category', async () => {
|
|||||||
exhaustive: true
|
exhaustive: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
expect(buildChangelogTest(customConfig, pullRequestsWithLabels)).toStrictEqual(
|
expect(buildChangelogTest(customConfig, pullRequestsWithLabels, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features and 🐛 Issues\n\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n`
|
`## 🚀 Features and 🐛 Issues\n\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -383,7 +386,7 @@ it('Deduplicate duplicated PRs', async () => {
|
|||||||
on_property: 'title',
|
on_property: 'title',
|
||||||
method: 'match'
|
method: 'match'
|
||||||
}
|
}
|
||||||
expect(buildChangelogTest(customConfig, pullRequestsWithLabels)).toStrictEqual(
|
expect(buildChangelogTest(customConfig, pullRequestsWithLabels, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features\n\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Fixes\n\n- [ABC-4321] - this is a PR 2 title message\n - PR: #2\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n`
|
`## 🚀 Features\n\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Fixes\n\n- [ABC-4321] - this is a PR 2 title message\n - PR: #2\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -397,7 +400,7 @@ it('Deduplicate duplicated PRs DESC', async () => {
|
|||||||
on_property: 'title',
|
on_property: 'title',
|
||||||
method: 'match'
|
method: 'match'
|
||||||
}
|
}
|
||||||
expect(buildChangelogTest(customConfig, pullRequestsWithLabels)).toStrictEqual(
|
expect(buildChangelogTest(customConfig, pullRequestsWithLabels, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features\n\n- [ABC-1234] - this is a PR 1 title message\n - PR: #1\n\n## 🐛 Fixes\n\n- [ABC-4321] - this is a PR 2 title message\n - PR: #2\n\n`
|
`## 🚀 Features\n\n- [ABC-1234] - this is a PR 1 title message\n - PR: #1\n\n## 🐛 Fixes\n\n- [ABC-4321] - this is a PR 2 title message\n - PR: #2\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -417,7 +420,7 @@ it('Reference PRs', async () => {
|
|||||||
method: 'replace',
|
method: 'replace',
|
||||||
target: '$1'
|
target: '$1'
|
||||||
}
|
}
|
||||||
expect(buildChangelogTest(customConfig, pullRequestsWithLabels)).toStrictEqual(`1 -- 2\n4 -- \n3 -- \n\n`)
|
expect(buildChangelogTest(customConfig, pullRequestsWithLabels, repositoryUtils)).toStrictEqual(`1 -- 2\n4 -- \n3 -- \n\n`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Use empty_content for empty category', async () => {
|
it('Use empty_content for empty category', async () => {
|
||||||
@@ -433,7 +436,7 @@ it('Use empty_content for empty category', async () => {
|
|||||||
labels: ['Feature']
|
labels: ['Feature']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
expect(buildChangelogTest(customConfig, pullRequestsWithLabels)).toStrictEqual(
|
expect(buildChangelogTest(customConfig, pullRequestsWithLabels, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features and 🐛 Issues\n\n- No PRs in this category\n\n## 🚀 Features\n\n- [ABC-1234] - this is a PR 1 title message\n - PR: #1\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n`
|
`## 🚀 Features and 🐛 Issues\n\n- No PRs in this category\n\n## 🚀 Features\n\n- [ABC-1234] - this is a PR 1 title message\n - PR: #1\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -504,7 +507,7 @@ it('Use exclude labels to not include a PR within a category.', async () => {
|
|||||||
exclude_labels: ['Fix']
|
exclude_labels: ['Fix']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
expect(buildChangelogTest(customConfig, pullRequestsWithLabels)).toStrictEqual(
|
expect(buildChangelogTest(customConfig, pullRequestsWithLabels, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features and 🐛 Issues\n\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n## 🚀 Features and/or 🐛 Issues But No 🐛 Fixes\n\n- [ABC-1234] - this is a PR 1 title message\n - PR: #1\n\n`
|
`## 🚀 Features and 🐛 Issues\n\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n## 🚀 Features and/or 🐛 Issues But No 🐛 Fixes\n\n- [ABC-1234] - this is a PR 1 title message\n - PR: #1\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -549,7 +552,7 @@ it('Extract custom placeholder from PR body and replace in global template', asy
|
|||||||
'#{{CHANGELOG}}\n\n#{{C_PLACEHOLER_2[2]}}\n\n#{{C_PLACEHOLER_2[*]}}#{{C_PLACEHOLDER_1[7]}}#{{C_PLACEHOLER_2[1493]}}#{{C_PLACEHOLER_4[*]}}#{{C_PLACEHOLER_4[0]}}#{{C_PLACEHOLER_3[1]}}'
|
'#{{CHANGELOG}}\n\n#{{C_PLACEHOLER_2[2]}}\n\n#{{C_PLACEHOLER_2[*]}}#{{C_PLACEHOLDER_1[7]}}#{{C_PLACEHOLER_2[1493]}}#{{C_PLACEHOLER_4[*]}}#{{C_PLACEHOLER_4[0]}}#{{C_PLACEHOLER_3[1]}}'
|
||||||
customConfig.pr_template = '#{{BODY}} ----> #{{C_PLACEHOLDER_1}}#{{C_PLACEHOLER_3}}'
|
customConfig.pr_template = '#{{BODY}} ----> #{{C_PLACEHOLDER_1}}#{{C_PLACEHOLER_3}}'
|
||||||
|
|
||||||
expect(buildChangelogTest(customConfig, mergedPullRequests)).toStrictEqual(
|
expect(buildChangelogTest(customConfig, mergedPullRequests, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features\n\nno magic body1 for this matter ----> - body1body1\nno magic body3 for this matter ----> - body3\n\n## 🐛 Fixes\n\nno magic body2 for this matter ----> - body2\nno magic body3 for this matter ----> - body3\n\n## 🧪 Others\n\nno magic body4 for this matter ----> - body4\n\n\n\n\n- ody3\n\n\n- ody1\n- ody2\n- ody3\n- ody4`
|
`## 🚀 Features\n\nno magic body1 for this matter ----> - body1body1\nno magic body3 for this matter ----> - body3\n\n## 🐛 Fixes\n\nno magic body2 for this matter ----> - body2\nno magic body3 for this matter ----> - body3\n\n## 🧪 Others\n\nno magic body4 for this matter ----> - body4\n\n\n\n\n- ody3\n\n\n- ody1\n- ody2\n- ody3\n- ody4`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -574,7 +577,7 @@ it('Use Rules to include a PR within a Category.', async () => {
|
|||||||
exhaustive: true
|
exhaustive: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
expect(buildChangelogTest(customConfig, pullRequestsWithLabels)).toStrictEqual(
|
expect(buildChangelogTest(customConfig, pullRequestsWithLabels, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features But No 🐛 Fixes and only merged with a title containing \`[ABC-1234]\`\n\n- [ABC-1234] - this is a PR 1 title message\n - PR: #1\n\n`
|
`## 🚀 Features But No 🐛 Fixes and only merged with a title containing \`[ABC-1234]\`\n\n- [ABC-1234] - this is a PR 1 title message\n - PR: #1\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -595,7 +598,9 @@ it('Use Rules to get all open PRs in a Category.', async () => {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
expect(buildChangelogTest(customConfig, prs)).toStrictEqual(`## Open PRs only\n\n- Still pending open pull request\n - PR: #6\n\n`)
|
expect(buildChangelogTest(customConfig, prs, repositoryUtils)).toStrictEqual(
|
||||||
|
`## Open PRs only\n\n- Still pending open pull request\n - PR: #6\n\n`
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Use Rules to get current open PR and merged categorised.', async () => {
|
it('Use Rules to get current open PR and merged categorised.', async () => {
|
||||||
@@ -633,7 +638,7 @@ it('Use Rules to get current open PR and merged categorised.', async () => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
expect(buildChangelogTest(customConfig, prs)).toStrictEqual(
|
expect(buildChangelogTest(customConfig, prs, repositoryUtils)).toStrictEqual(
|
||||||
`## 🚀 Features\n\n- [ABC-1234] - this is a PR 1 title message\n - PR: #1\n- Still pending open pull request (Current)\n - PR: #6\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Issues\n\n- [ABC-4321] - this is a PR 2 title message\n - PR: #2\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n`
|
`## 🚀 Features\n\n- [ABC-1234] - this is a PR 1 title message\n - PR: #1\n- Still pending open pull request (Current)\n - PR: #6\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n## 🐛 Issues\n\n- [ABC-4321] - this is a PR 2 title message\n - PR: #2\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -665,24 +670,7 @@ it('Use Rules to get all open PRs in one Category and merged categorised.', asyn
|
|||||||
exhaustive: true
|
exhaustive: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
expect(buildChangelogTest(customConfig, prs)).toStrictEqual(
|
expect(buildChangelogTest(customConfig, prs, repositoryUtils)).toStrictEqual(
|
||||||
`## Open PRs only\n\n- Still pending open pull request\n - PR: #6\n\n## 🚀 Features and 🐛 Issues\n\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n`
|
`## Open PRs only\n\n- Still pending open pull request\n - PR: #6\n\n## 🚀 Features and 🐛 Issues\n\n- [ABC-1234] - this is a PR 3 title message\n - PR: #3\n\n`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
function buildChangelogTest(config: Configuration, prs: PullRequestInfo[]): string {
|
|
||||||
return buildChangelog(DefaultDiffInfo, prs, {
|
|
||||||
owner: 'mikepenz',
|
|
||||||
repo: 'test-repo',
|
|
||||||
fromTag: {name: '1.0.0'},
|
|
||||||
toTag: {name: '2.0.0'},
|
|
||||||
includeOpen: false,
|
|
||||||
failOnError: false,
|
|
||||||
fetchReviewers: false,
|
|
||||||
fetchReleaseInformation: false,
|
|
||||||
fetchReviews: false,
|
|
||||||
commitMode: false,
|
|
||||||
configuration: config,
|
|
||||||
repositoryUtils: repositoryUtils
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import moment from 'moment'
|
||||||
|
import {DefaultConfiguration} from '../src/configuration'
|
||||||
|
import {PullRequestInfo} from '../src/pr-collector/pullRequests'
|
||||||
|
import {GithubRepository} from '../src/repositories/GithubRepository'
|
||||||
|
import {clear} from '../src/transform'
|
||||||
|
import {buildChangelogTest, buildPullRequeset} from './utils'
|
||||||
|
|
||||||
|
jest.setTimeout(180000)
|
||||||
|
clear()
|
||||||
|
|
||||||
|
const repositoryUtils = new GithubRepository(process.env.GITEA_TOKEN || '', undefined, '.')
|
||||||
|
|
||||||
|
// test set of PRs with lables predefined
|
||||||
|
const pullRequestsWithLabels: PullRequestInfo[] = []
|
||||||
|
pullRequestsWithLabels.push(
|
||||||
|
buildPullRequeset(1, 'Core Feature Ticket', ['core', 'feature']),
|
||||||
|
buildPullRequeset(2, 'Core Bug Ticket', ['core', 'bug']),
|
||||||
|
buildPullRequeset(3, 'Mobile Feature Ticket', ['mobile', 'feature']),
|
||||||
|
buildPullRequeset(4, 'Mobile Bug Ticket', ['mobile', 'bug']),
|
||||||
|
buildPullRequeset(5, 'Mobile & Core Feature Ticket', ['core', 'mobile', 'feature']),
|
||||||
|
buildPullRequeset(6, 'Mobile & Core Bug Ticket', ['core', 'mobile', 'bug']),
|
||||||
|
buildPullRequeset(7, 'Mobile & Core Bug Bug Ticket', ['core', 'mobile', 'bug', 'fancy-bug']),
|
||||||
|
buildPullRequeset(8, 'Core Ticket', ['core'])
|
||||||
|
)
|
||||||
|
|
||||||
|
it('Match multiple labels exhaustive for category', async () => {
|
||||||
|
const customConfig = Object.assign({}, DefaultConfiguration)
|
||||||
|
customConfig.pr_template = '- #{{TITLE}}'
|
||||||
|
customConfig.categories = [
|
||||||
|
{
|
||||||
|
title: '## Core',
|
||||||
|
labels: ['core'],
|
||||||
|
consume: true,
|
||||||
|
categories: [
|
||||||
|
{
|
||||||
|
title: '### 🚀 Features',
|
||||||
|
labels: ['feature']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '### 🧪 Bug',
|
||||||
|
labels: ['bug'],
|
||||||
|
categories: [
|
||||||
|
{
|
||||||
|
title: '#### 🧪 Bug Bug',
|
||||||
|
labels: ['fancy-bug']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '## Mobile',
|
||||||
|
labels: ['mobile'],
|
||||||
|
consume: true,
|
||||||
|
categories: [
|
||||||
|
{
|
||||||
|
title: '### 🚀 Features',
|
||||||
|
labels: ['feature']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '### 🧪 Bug',
|
||||||
|
labels: ['bug']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '## Desktop',
|
||||||
|
labels: ['desktop'],
|
||||||
|
consume: true,
|
||||||
|
categories: [
|
||||||
|
{
|
||||||
|
title: '### 🚀 Features',
|
||||||
|
labels: ['feature']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '### 🧪 Bug',
|
||||||
|
labels: ['bug']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const built = buildChangelogTest(customConfig, pullRequestsWithLabels, repositoryUtils)
|
||||||
|
expect(built).toStrictEqual(`## Core\n\n- Core Ticket\n\n### 🚀 Features\n\n- Core Feature Ticket\n- Mobile & Core Feature Ticket\n\n### 🧪 Bug\n\n- Core Bug Ticket\n- Mobile & Core Bug Ticket\n\n#### 🧪 Bug Bug\n\n- Mobile & Core Bug Bug Ticket\n\n## Mobile\n\n\n### 🚀 Features\n\n- Mobile Feature Ticket\n\n### 🧪 Bug\n\n- Mobile Bug Ticket\n\n`)
|
||||||
|
})
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import {Configuration} from '../src/configuration'
|
||||||
|
import {DefaultDiffInfo} from '../src/pr-collector/commits'
|
||||||
|
import {PullRequestInfo} from '../src/pr-collector/pullRequests'
|
||||||
|
import {buildChangelog} from '../src/transform'
|
||||||
|
import {BaseRepository} from '../src/repositories/BaseRepository'
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
|
export const buildChangelogTest = (config: Configuration, prs: PullRequestInfo[], repositoryUtils: BaseRepository): string => {
|
||||||
|
return buildChangelog(DefaultDiffInfo, prs, {
|
||||||
|
owner: 'mikepenz',
|
||||||
|
repo: 'test-repo',
|
||||||
|
fromTag: {name: '1.0.0'},
|
||||||
|
toTag: {name: '2.0.0'},
|
||||||
|
includeOpen: false,
|
||||||
|
failOnError: false,
|
||||||
|
fetchReviewers: false,
|
||||||
|
fetchReleaseInformation: false,
|
||||||
|
fetchReviews: false,
|
||||||
|
commitMode: false,
|
||||||
|
configuration: config,
|
||||||
|
repositoryUtils
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const buildPullRequeset = (number: number, title: string, labels: string[] = ['feature']): PullRequestInfo => {
|
||||||
|
return {
|
||||||
|
number,
|
||||||
|
title,
|
||||||
|
htmlURL: '',
|
||||||
|
baseBranch: '',
|
||||||
|
createdAt: moment(),
|
||||||
|
mergedAt: moment(),
|
||||||
|
mergeCommitSha: 'sha',
|
||||||
|
author: 'Author',
|
||||||
|
repoName: 'test-repo',
|
||||||
|
labels,
|
||||||
|
milestone: '',
|
||||||
|
body: '',
|
||||||
|
assignees: [],
|
||||||
|
requestedReviewers: [],
|
||||||
|
approvedReviewers: [],
|
||||||
|
status: 'merged'
|
||||||
|
}
|
||||||
|
}
|
||||||
+133
-67
@@ -2500,13 +2500,18 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.replaceEmptyTemplate = exports.buildChangelog = void 0;
|
exports.replaceEmptyTemplate = exports.buildChangelog = exports.clear = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const utils_1 = __nccwpck_require__(918);
|
const utils_1 = __nccwpck_require__(918);
|
||||||
const pullRequests_1 = __nccwpck_require__(4012);
|
const pullRequests_1 = __nccwpck_require__(4012);
|
||||||
const regexUtils_1 = __nccwpck_require__(5351);
|
const regexUtils_1 = __nccwpck_require__(5351);
|
||||||
const regexUtils_2 = __nccwpck_require__(2364);
|
const regexUtils_2 = __nccwpck_require__(2364);
|
||||||
const EMPTY_MAP = new Map();
|
const EMPTY_MAP = new Map();
|
||||||
|
let CLEAR = false;
|
||||||
|
function clear() {
|
||||||
|
CLEAR = true;
|
||||||
|
}
|
||||||
|
exports.clear = clear;
|
||||||
function buildChangelog(diffInfo, origPrs, options) {
|
function buildChangelog(diffInfo, origPrs, options) {
|
||||||
core.startGroup('📦 Build changelog');
|
core.startGroup('📦 Build changelog');
|
||||||
let prs = origPrs;
|
let prs = origPrs;
|
||||||
@@ -2616,18 +2621,21 @@ function buildChangelog(diffInfo, origPrs, options) {
|
|||||||
core.info(`ℹ️ Used ${validatedTransformers.length} transformers to adjust message`);
|
core.info(`ℹ️ Used ${validatedTransformers.length} transformers to adjust message`);
|
||||||
core.info(`✒️ Wrote messages for ${prs.length} pull requests`);
|
core.info(`✒️ Wrote messages for ${prs.length} pull requests`);
|
||||||
// bring PRs into the order of categories
|
// bring PRs into the order of categories
|
||||||
const categorized = new Map();
|
|
||||||
const categories = config.categories;
|
const categories = config.categories;
|
||||||
const ignoredLabels = config.ignore_labels;
|
const ignoredLabels = config.ignore_labels;
|
||||||
for (const category of categories) {
|
const flatCategories = flatten(config.categories);
|
||||||
categorized.set(category, []);
|
|
||||||
}
|
|
||||||
const categorizedPrs = [];
|
const categorizedPrs = [];
|
||||||
const ignoredPrs = [];
|
const ignoredPrs = [];
|
||||||
const openPrs = [];
|
const openPrs = [];
|
||||||
const uncategorizedPrs = [];
|
const uncategorizedPrs = [];
|
||||||
|
// set-up the category object
|
||||||
|
for (const category of flatCategories) {
|
||||||
|
if (CLEAR || !category.entries) {
|
||||||
|
category.entries = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
// bring elements in order
|
// bring elements in order
|
||||||
for (const [pr, body] of transformedMap) {
|
prLoop: for (const [pr, body] of transformedMap) {
|
||||||
if ((0, utils_1.haveCommonElementsArr)(ignoredLabels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
|
if ((0, utils_1.haveCommonElementsArr)(ignoredLabels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
|
||||||
ignoredPrs.push(body);
|
ignoredPrs.push(body);
|
||||||
continue;
|
continue;
|
||||||
@@ -2636,55 +2644,17 @@ function buildChangelog(diffInfo, origPrs, options) {
|
|||||||
openPrs.push(body);
|
openPrs.push(body);
|
||||||
}
|
}
|
||||||
let matchedOnce = false; // in case we matched once at least, the PR can't be uncategorized
|
let matchedOnce = false; // in case we matched once at least, the PR can't be uncategorized
|
||||||
for (const [category, pullRequests] of categorized) {
|
for (const category of categories) {
|
||||||
let matched = false; // check if we matched within the given category
|
const [matched, consumed] = recursiveCategorizePr(category, pr, body);
|
||||||
// check if any exclude label matches
|
if (consumed) {
|
||||||
if (category.exclude_labels !== undefined) {
|
continue prLoop;
|
||||||
if ((0, utils_1.haveCommonElementsArr)(category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
|
|
||||||
if (core.isDebug()) {
|
|
||||||
const excludeLabels = JSON.stringify(category.exclude_labels);
|
|
||||||
core.debug(` PR ${pr.number} with labels: ${pr.labels} excluded from category via exclude label: ${excludeLabels}`);
|
|
||||||
}
|
|
||||||
continue; // one of the exclude labels matched, skip the PR for this category
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// in case we have exhaustive matching enabled, and have labels and/or rules
|
|
||||||
// validate for an exhaustive match (e.g. every provided rule applies)
|
|
||||||
if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) {
|
|
||||||
if (category.labels !== undefined) {
|
|
||||||
matched = (0, utils_1.haveEveryElementsArr)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels);
|
|
||||||
}
|
|
||||||
let exhaustive_rules = true;
|
|
||||||
if (category.exhaustive_rules !== undefined) {
|
|
||||||
exhaustive_rules = category.exhaustive_rules;
|
|
||||||
}
|
|
||||||
if ((matched || category.labels === undefined) && category.rules !== undefined) {
|
|
||||||
matched = (0, regexUtils_2.matchesRules)(category.rules, pr, exhaustive_rules);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// if not exhaustive, do individual matches
|
|
||||||
if (category.labels !== undefined) {
|
|
||||||
// check if either any of the labels applies
|
|
||||||
matched = (0, utils_1.haveCommonElementsArr)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels);
|
|
||||||
}
|
|
||||||
let exhaustive_rules = false;
|
|
||||||
if (category.exhaustive_rules !== undefined) {
|
|
||||||
exhaustive_rules = category.exhaustive_rules;
|
|
||||||
}
|
|
||||||
if (!matched && category.rules !== undefined) {
|
|
||||||
// if no label did apply, check if any rule applies
|
|
||||||
matched = (0, regexUtils_2.matchesRules)(category.rules, pr, exhaustive_rules);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (matched) {
|
|
||||||
pullRequests.push(body); // if matched add the PR to the list
|
|
||||||
}
|
}
|
||||||
matchedOnce = matchedOnce || matched;
|
matchedOnce = matchedOnce || matched;
|
||||||
}
|
}
|
||||||
if (!matchedOnce) {
|
if (!matchedOnce) {
|
||||||
// we allow to have pull requests included in an "uncategorized" category
|
// we allow to have pull requests included in an "uncategorized" category
|
||||||
for (const [category, pullRequests] of categorized) {
|
for (const category of flatCategories) {
|
||||||
|
const pullRequests = category.entries || [];
|
||||||
if ((category.labels === undefined || category.labels.length === 0) && category.rules === undefined) {
|
if ((category.labels === undefined || category.labels.length === 0) && category.rules === undefined) {
|
||||||
// check if any exclude label matches for the "uncategorized" category
|
// check if any exclude label matches for the "uncategorized" category
|
||||||
if (category.exclude_labels !== undefined) {
|
if (category.exclude_labels !== undefined) {
|
||||||
@@ -2711,26 +2681,16 @@ function buildChangelog(diffInfo, origPrs, options) {
|
|||||||
}
|
}
|
||||||
core.info(`ℹ️ Ordered all pull requests into ${categories.length} categories`);
|
core.info(`ℹ️ Ordered all pull requests into ${categories.length} categories`);
|
||||||
// serialize and provide the categorized content as json
|
// serialize and provide the categorized content as json
|
||||||
const transformedCategorized = Array.from(categorized).reduce((obj, [key, value]) => Object.assign(obj, { [key.key || key.title]: value }), {});
|
const transformedCategorized = {};
|
||||||
|
for (const category of flatCategories) {
|
||||||
|
Object.assign(transformedCategorized, { [category.key || category.title]: category.entries });
|
||||||
|
}
|
||||||
core.setOutput('categorized', JSON.stringify(transformedCategorized));
|
core.setOutput('categorized', JSON.stringify(transformedCategorized));
|
||||||
// construct final changelog
|
// construct final changelog
|
||||||
let changelog = '';
|
let changelog = '';
|
||||||
for (const [category, pullRequests] of categorized) {
|
for (const category of flatCategories) {
|
||||||
if (pullRequests.length > 0) {
|
const pullRequests = category.entries || [];
|
||||||
if (category.title) {
|
changelog = attachCategoryChangelog(changelog, category, pullRequests);
|
||||||
changelog = `${changelog + category.title}\n\n`;
|
|
||||||
}
|
|
||||||
for (const pr of pullRequests) {
|
|
||||||
changelog = `${changelog + pr}\n`;
|
|
||||||
}
|
|
||||||
changelog = `${changelog}\n`; // add space between sections
|
|
||||||
}
|
|
||||||
else if (category.empty_content !== undefined) {
|
|
||||||
if (category.title) {
|
|
||||||
changelog = `${changelog + category.title}\n\n`;
|
|
||||||
}
|
|
||||||
changelog = `${changelog + category.empty_content}\n\n`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
core.info(`✒️ Wrote ${categorizedPrs.length} categorized pull requests down`);
|
core.info(`✒️ Wrote ${categorizedPrs.length} categorized pull requests down`);
|
||||||
if (core.isDebug()) {
|
if (core.isDebug()) {
|
||||||
@@ -2801,6 +2761,92 @@ function buildChangelog(diffInfo, origPrs, options) {
|
|||||||
return transformedChangelog;
|
return transformedChangelog;
|
||||||
}
|
}
|
||||||
exports.buildChangelog = buildChangelog;
|
exports.buildChangelog = buildChangelog;
|
||||||
|
function recursiveCategorizePr(category, pr, body) {
|
||||||
|
let matched = false;
|
||||||
|
let consumed = false;
|
||||||
|
const matchesParent = categorizePr(category, pr);
|
||||||
|
// only do children if parent also matches
|
||||||
|
if (category.categories && matchesParent) {
|
||||||
|
for (const childCategory of category.categories) {
|
||||||
|
const [childMatched, childConsumed] = recursiveCategorizePr(childCategory, pr, body);
|
||||||
|
matched = matched || childMatched; // at least one time it matched
|
||||||
|
consumed = childConsumed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if consumed we don't handle it anymore, as it was matched in a child, don't handle anymore
|
||||||
|
if (!consumed && !matched) {
|
||||||
|
const pullRequests = category.entries || [];
|
||||||
|
matched = matchesParent;
|
||||||
|
if (matched) {
|
||||||
|
pullRequests.push(body); // if matched add the PR to the list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matched && category.consume) {
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
return [matched, consumed];
|
||||||
|
}
|
||||||
|
function categorizePr(category, pr) {
|
||||||
|
let matched = false; // check if we matched within the given category
|
||||||
|
// check if any exclude label matches
|
||||||
|
if (category.exclude_labels !== undefined) {
|
||||||
|
if ((0, utils_1.haveCommonElementsArr)(category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
|
||||||
|
if (core.isDebug()) {
|
||||||
|
const excludeLabels = JSON.stringify(category.exclude_labels);
|
||||||
|
core.debug(` PR ${pr.number} with labels: ${pr.labels} excluded from category via exclude label: ${excludeLabels}`);
|
||||||
|
}
|
||||||
|
return false; // one of the exclude labels matched, skip the PR for this category
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// in case we have exhaustive matching enabled, and have labels and/or rules
|
||||||
|
// validate for an exhaustive match (e.g. every provided rule applies)
|
||||||
|
if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) {
|
||||||
|
if (category.labels !== undefined) {
|
||||||
|
matched = (0, utils_1.haveEveryElementsArr)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels);
|
||||||
|
}
|
||||||
|
let exhaustive_rules = true;
|
||||||
|
if (category.exhaustive_rules !== undefined) {
|
||||||
|
exhaustive_rules = category.exhaustive_rules;
|
||||||
|
}
|
||||||
|
if ((matched || category.labels === undefined) && category.rules !== undefined) {
|
||||||
|
matched = (0, regexUtils_2.matchesRules)(category.rules, pr, exhaustive_rules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// if not exhaustive, do individual matches
|
||||||
|
if (category.labels !== undefined) {
|
||||||
|
// check if either any of the labels applies
|
||||||
|
matched = (0, utils_1.haveCommonElementsArr)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels);
|
||||||
|
}
|
||||||
|
let exhaustive_rules = false;
|
||||||
|
if (category.exhaustive_rules !== undefined) {
|
||||||
|
exhaustive_rules = category.exhaustive_rules;
|
||||||
|
}
|
||||||
|
if (!matched && category.rules !== undefined) {
|
||||||
|
// if no label did apply, check if any rule applies
|
||||||
|
matched = (0, regexUtils_2.matchesRules)(category.rules, pr, exhaustive_rules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matched;
|
||||||
|
}
|
||||||
|
function attachCategoryChangelog(changelog, category, pullRequests) {
|
||||||
|
if (pullRequests.length > 0 || hasChildWithEntries(category)) {
|
||||||
|
if (category.title) {
|
||||||
|
changelog = `${changelog + category.title}\n\n`;
|
||||||
|
}
|
||||||
|
for (const pr of pullRequests) {
|
||||||
|
changelog = `${changelog + pr}\n`;
|
||||||
|
}
|
||||||
|
changelog = `${changelog}\n`; // add space between sections
|
||||||
|
}
|
||||||
|
else if (category.empty_content !== undefined) {
|
||||||
|
if (category.title) {
|
||||||
|
changelog = `${changelog + category.title}\n\n`;
|
||||||
|
}
|
||||||
|
changelog = `${changelog + category.empty_content}\n\n`;
|
||||||
|
}
|
||||||
|
return changelog;
|
||||||
|
}
|
||||||
function replaceEmptyTemplate(template, options) {
|
function replaceEmptyTemplate(template, options) {
|
||||||
const placeholders = new Map();
|
const placeholders = new Map();
|
||||||
for (const ph of options.configuration.custom_placeholders || []) {
|
for (const ph of options.configuration.custom_placeholders || []) {
|
||||||
@@ -3011,6 +3057,26 @@ function extractValuesFromString(value, extractor) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function flatten(categories) {
|
||||||
|
if (!categories) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return categories.reduce(function (r, i) {
|
||||||
|
return r.concat([i]).concat(flatten(i.categories));
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
function hasChildWithEntries(category) {
|
||||||
|
var _a;
|
||||||
|
const categories = category.categories;
|
||||||
|
if (!categories || categories.length === 0) {
|
||||||
|
return (((_a = category.entries) === null || _a === void 0 ? void 0 : _a.length) || 0) > 0;
|
||||||
|
}
|
||||||
|
let hasEntries = false;
|
||||||
|
for (const cat of categories) {
|
||||||
|
hasEntries = hasEntries || hasChildWithEntries(cat);
|
||||||
|
}
|
||||||
|
return hasEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -30,6 +30,9 @@ export interface Category {
|
|||||||
exhaustive?: boolean // requires all labels to be present in the PR
|
exhaustive?: boolean // requires all labels to be present in the PR
|
||||||
exhaustive_rules?: boolean // requires all rules to be present in the PR (if not set, defaults to exhaustive value)
|
exhaustive_rules?: boolean // requires all rules to be present in the PR (if not set, defaults to exhaustive value)
|
||||||
empty_content?: string // if the category has no matching PRs, this content will be used. If not set, the category will be skipped in the changelog.
|
empty_content?: string // if the category has no matching PRs, this content will be used. If not set, the category will be skipped in the changelog.
|
||||||
|
categories?: Category[] // allows for nested categories, items matched for a child category won't show up in the parent
|
||||||
|
consume?: boolean // defines if the matched PR will be consumed by this category. Consumed PRs won't show up in any category *after*
|
||||||
|
entries?: string[] // array of single changelog entries, used to construc the changelog. (this is filled during the build)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+151
-82
@@ -16,6 +16,11 @@ import {ReleaseNotesOptions} from './releaseNotesBuilder'
|
|||||||
import {matchesRules} from './regexUtils'
|
import {matchesRules} from './regexUtils'
|
||||||
|
|
||||||
const EMPTY_MAP = new Map<string, string>()
|
const EMPTY_MAP = new Map<string, string>()
|
||||||
|
let CLEAR = false
|
||||||
|
|
||||||
|
export function clear(): void {
|
||||||
|
CLEAR = true
|
||||||
|
}
|
||||||
|
|
||||||
export interface PullRequestData extends PullRequestInfo {
|
export interface PullRequestData extends PullRequestInfo {
|
||||||
childPrs?: PullRequestInfo[]
|
childPrs?: PullRequestInfo[]
|
||||||
@@ -111,7 +116,6 @@ export function buildChangelog(diffInfo: DiffInfo, origPrs: PullRequestInfo[], o
|
|||||||
for (const label of extracted) {
|
for (const label of extracted) {
|
||||||
pr.labels.push(label)
|
pr.labels.push(label)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (core.isDebug()) {
|
if (core.isDebug()) {
|
||||||
core.debug(` Extracted the following labels (${JSON.stringify(extracted)}) for PR ${pr.number}`)
|
core.debug(` Extracted the following labels (${JSON.stringify(extracted)}) for PR ${pr.number}`)
|
||||||
}
|
}
|
||||||
@@ -136,21 +140,24 @@ export function buildChangelog(diffInfo: DiffInfo, origPrs: PullRequestInfo[], o
|
|||||||
core.info(`✒️ Wrote messages for ${prs.length} pull requests`)
|
core.info(`✒️ Wrote messages for ${prs.length} pull requests`)
|
||||||
|
|
||||||
// bring PRs into the order of categories
|
// bring PRs into the order of categories
|
||||||
const categorized = new Map<Category, string[]>()
|
|
||||||
const categories = config.categories
|
const categories = config.categories
|
||||||
const ignoredLabels = config.ignore_labels
|
const ignoredLabels = config.ignore_labels
|
||||||
|
|
||||||
for (const category of categories) {
|
const flatCategories = flatten(config.categories)
|
||||||
categorized.set(category, [])
|
|
||||||
}
|
|
||||||
|
|
||||||
const categorizedPrs: string[] = []
|
const categorizedPrs: string[] = []
|
||||||
const ignoredPrs: string[] = []
|
const ignoredPrs: string[] = []
|
||||||
const openPrs: string[] = []
|
const openPrs: string[] = []
|
||||||
const uncategorizedPrs: string[] = []
|
const uncategorizedPrs: string[] = []
|
||||||
|
|
||||||
|
// set-up the category object
|
||||||
|
for (const category of flatCategories) {
|
||||||
|
if (CLEAR || !category.entries) {
|
||||||
|
category.entries = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// bring elements in order
|
// bring elements in order
|
||||||
for (const [pr, body] of transformedMap) {
|
prLoop: for (const [pr, body] of transformedMap) {
|
||||||
if (
|
if (
|
||||||
haveCommonElementsArr(
|
haveCommonElementsArr(
|
||||||
ignoredLabels.map(lbl => lbl.toLocaleLowerCase('en')),
|
ignoredLabels.map(lbl => lbl.toLocaleLowerCase('en')),
|
||||||
@@ -166,67 +173,18 @@ export function buildChangelog(diffInfo: DiffInfo, origPrs: PullRequestInfo[], o
|
|||||||
}
|
}
|
||||||
|
|
||||||
let matchedOnce = false // in case we matched once at least, the PR can't be uncategorized
|
let matchedOnce = false // in case we matched once at least, the PR can't be uncategorized
|
||||||
for (const [category, pullRequests] of categorized) {
|
for (const category of categories) {
|
||||||
let matched = false // check if we matched within the given category
|
const [matched, consumed] = recursiveCategorizePr(category, pr, body)
|
||||||
// check if any exclude label matches
|
if (consumed) {
|
||||||
if (category.exclude_labels !== undefined) {
|
continue prLoop
|
||||||
if (
|
|
||||||
haveCommonElementsArr(
|
|
||||||
category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
|
||||||
pr.labels
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
if (core.isDebug()) {
|
|
||||||
const excludeLabels = JSON.stringify(category.exclude_labels)
|
|
||||||
core.debug(` PR ${pr.number} with labels: ${pr.labels} excluded from category via exclude label: ${excludeLabels}`)
|
|
||||||
}
|
|
||||||
continue // one of the exclude labels matched, skip the PR for this category
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// in case we have exhaustive matching enabled, and have labels and/or rules
|
|
||||||
// validate for an exhaustive match (e.g. every provided rule applies)
|
|
||||||
if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) {
|
|
||||||
if (category.labels !== undefined) {
|
|
||||||
matched = haveEveryElementsArr(
|
|
||||||
category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
|
||||||
pr.labels
|
|
||||||
)
|
|
||||||
}
|
|
||||||
let exhaustive_rules = true
|
|
||||||
if (category.exhaustive_rules !== undefined) {
|
|
||||||
exhaustive_rules = category.exhaustive_rules
|
|
||||||
}
|
|
||||||
if ((matched || category.labels === undefined) && category.rules !== undefined) {
|
|
||||||
matched = matchesRules(category.rules, pr, exhaustive_rules)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if not exhaustive, do individual matches
|
|
||||||
if (category.labels !== undefined) {
|
|
||||||
// check if either any of the labels applies
|
|
||||||
matched = haveCommonElementsArr(
|
|
||||||
category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
|
||||||
pr.labels
|
|
||||||
)
|
|
||||||
}
|
|
||||||
let exhaustive_rules = false
|
|
||||||
if (category.exhaustive_rules !== undefined) {
|
|
||||||
exhaustive_rules = category.exhaustive_rules
|
|
||||||
}
|
|
||||||
if (!matched && category.rules !== undefined) {
|
|
||||||
// if no label did apply, check if any rule applies
|
|
||||||
matched = matchesRules(category.rules, pr, exhaustive_rules)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (matched) {
|
|
||||||
pullRequests.push(body) // if matched add the PR to the list
|
|
||||||
}
|
}
|
||||||
matchedOnce = matchedOnce || matched
|
matchedOnce = matchedOnce || matched
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!matchedOnce) {
|
if (!matchedOnce) {
|
||||||
// we allow to have pull requests included in an "uncategorized" category
|
// we allow to have pull requests included in an "uncategorized" category
|
||||||
for (const [category, pullRequests] of categorized) {
|
for (const category of flatCategories) {
|
||||||
|
const pullRequests = category.entries || []
|
||||||
if ((category.labels === undefined || category.labels.length === 0) && category.rules === undefined) {
|
if ((category.labels === undefined || category.labels.length === 0) && category.rules === undefined) {
|
||||||
// check if any exclude label matches for the "uncategorized" category
|
// check if any exclude label matches for the "uncategorized" category
|
||||||
if (category.exclude_labels !== undefined) {
|
if (category.exclude_labels !== undefined) {
|
||||||
@@ -260,30 +218,17 @@ export function buildChangelog(diffInfo: DiffInfo, origPrs: PullRequestInfo[], o
|
|||||||
core.info(`ℹ️ Ordered all pull requests into ${categories.length} categories`)
|
core.info(`ℹ️ Ordered all pull requests into ${categories.length} categories`)
|
||||||
|
|
||||||
// serialize and provide the categorized content as json
|
// serialize and provide the categorized content as json
|
||||||
const transformedCategorized = Array.from(categorized).reduce(
|
const transformedCategorized = {}
|
||||||
(obj, [key, value]) => Object.assign(obj, {[key.key || key.title]: value}),
|
for (const category of flatCategories) {
|
||||||
{}
|
Object.assign(transformedCategorized, {[category.key || category.title]: category.entries})
|
||||||
)
|
}
|
||||||
core.setOutput('categorized', JSON.stringify(transformedCategorized))
|
core.setOutput('categorized', JSON.stringify(transformedCategorized))
|
||||||
|
|
||||||
// construct final changelog
|
// construct final changelog
|
||||||
let changelog = ''
|
let changelog = ''
|
||||||
for (const [category, pullRequests] of categorized) {
|
for (const category of flatCategories) {
|
||||||
if (pullRequests.length > 0) {
|
const pullRequests = category.entries || []
|
||||||
if (category.title) {
|
changelog = attachCategoryChangelog(changelog, category, pullRequests)
|
||||||
changelog = `${changelog + category.title}\n\n`
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const pr of pullRequests) {
|
|
||||||
changelog = `${changelog + pr}\n`
|
|
||||||
}
|
|
||||||
changelog = `${changelog}\n` // add space between sections
|
|
||||||
} else if (category.empty_content !== undefined) {
|
|
||||||
if (category.title) {
|
|
||||||
changelog = `${changelog + category.title}\n\n`
|
|
||||||
}
|
|
||||||
changelog = `${changelog + category.empty_content}\n\n`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
core.info(`✒️ Wrote ${categorizedPrs.length} categorized pull requests down`)
|
core.info(`✒️ Wrote ${categorizedPrs.length} categorized pull requests down`)
|
||||||
if (core.isDebug()) {
|
if (core.isDebug()) {
|
||||||
@@ -359,6 +304,109 @@ export function buildChangelog(diffInfo: DiffInfo, origPrs: PullRequestInfo[], o
|
|||||||
return transformedChangelog
|
return transformedChangelog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function recursiveCategorizePr(category: Category, pr: PullRequestInfo, body: string): boolean[] {
|
||||||
|
let matched = false
|
||||||
|
let consumed = false
|
||||||
|
|
||||||
|
const matchesParent = categorizePr(category, pr)
|
||||||
|
|
||||||
|
// only do children if parent also matches
|
||||||
|
if (category.categories && matchesParent) {
|
||||||
|
for (const childCategory of category.categories) {
|
||||||
|
const [childMatched, childConsumed] = recursiveCategorizePr(childCategory, pr, body)
|
||||||
|
matched = matched || childMatched // at least one time it matched
|
||||||
|
consumed = childConsumed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if consumed we don't handle it anymore, as it was matched in a child, don't handle anymore
|
||||||
|
if (!consumed && !matched) {
|
||||||
|
const pullRequests = category.entries || []
|
||||||
|
matched = matchesParent
|
||||||
|
if (matched) {
|
||||||
|
pullRequests.push(body) // if matched add the PR to the list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matched && category.consume) {
|
||||||
|
consumed = true
|
||||||
|
}
|
||||||
|
return [matched, consumed]
|
||||||
|
}
|
||||||
|
|
||||||
|
function categorizePr(category: Category, pr: PullRequestInfo): boolean {
|
||||||
|
let matched = false // check if we matched within the given category
|
||||||
|
// check if any exclude label matches
|
||||||
|
if (category.exclude_labels !== undefined) {
|
||||||
|
if (
|
||||||
|
haveCommonElementsArr(
|
||||||
|
category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
||||||
|
pr.labels
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (core.isDebug()) {
|
||||||
|
const excludeLabels = JSON.stringify(category.exclude_labels)
|
||||||
|
core.debug(` PR ${pr.number} with labels: ${pr.labels} excluded from category via exclude label: ${excludeLabels}`)
|
||||||
|
}
|
||||||
|
return false // one of the exclude labels matched, skip the PR for this category
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case we have exhaustive matching enabled, and have labels and/or rules
|
||||||
|
// validate for an exhaustive match (e.g. every provided rule applies)
|
||||||
|
if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) {
|
||||||
|
if (category.labels !== undefined) {
|
||||||
|
matched = haveEveryElementsArr(
|
||||||
|
category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
||||||
|
pr.labels
|
||||||
|
)
|
||||||
|
}
|
||||||
|
let exhaustive_rules = true
|
||||||
|
if (category.exhaustive_rules !== undefined) {
|
||||||
|
exhaustive_rules = category.exhaustive_rules
|
||||||
|
}
|
||||||
|
if ((matched || category.labels === undefined) && category.rules !== undefined) {
|
||||||
|
matched = matchesRules(category.rules, pr, exhaustive_rules)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if not exhaustive, do individual matches
|
||||||
|
if (category.labels !== undefined) {
|
||||||
|
// check if either any of the labels applies
|
||||||
|
matched = haveCommonElementsArr(
|
||||||
|
category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
||||||
|
pr.labels
|
||||||
|
)
|
||||||
|
}
|
||||||
|
let exhaustive_rules = false
|
||||||
|
if (category.exhaustive_rules !== undefined) {
|
||||||
|
exhaustive_rules = category.exhaustive_rules
|
||||||
|
}
|
||||||
|
if (!matched && category.rules !== undefined) {
|
||||||
|
// if no label did apply, check if any rule applies
|
||||||
|
matched = matchesRules(category.rules, pr, exhaustive_rules)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matched
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachCategoryChangelog(changelog: string, category: Category, pullRequests: string[]): string {
|
||||||
|
if (pullRequests.length > 0 || hasChildWithEntries(category)) {
|
||||||
|
if (category.title) {
|
||||||
|
changelog = `${changelog + category.title}\n\n`
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const pr of pullRequests) {
|
||||||
|
changelog = `${changelog + pr}\n`
|
||||||
|
}
|
||||||
|
changelog = `${changelog}\n` // add space between sections
|
||||||
|
} else if (category.empty_content !== undefined) {
|
||||||
|
if (category.title) {
|
||||||
|
changelog = `${changelog + category.title}\n\n`
|
||||||
|
}
|
||||||
|
changelog = `${changelog + category.empty_content}\n\n`
|
||||||
|
}
|
||||||
|
return changelog
|
||||||
|
}
|
||||||
|
|
||||||
export function replaceEmptyTemplate(template: string, options: ReleaseNotesOptions): string {
|
export function replaceEmptyTemplate(template: string, options: ReleaseNotesOptions): string {
|
||||||
const placeholders = new Map<string, Placeholder[]>()
|
const placeholders = new Map<string, Placeholder[]>()
|
||||||
for (const ph of options.configuration.custom_placeholders || []) {
|
for (const ph of options.configuration.custom_placeholders || []) {
|
||||||
@@ -627,3 +675,24 @@ function extractValuesFromString(value: string, extractor: RegexTransformer): st
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function flatten(categories?: Category[]): Category[] {
|
||||||
|
if (!categories) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return categories.reduce(function (r: Category[], i) {
|
||||||
|
return r.concat([i]).concat(flatten(i.categories))
|
||||||
|
}, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasChildWithEntries(category: Category): boolean {
|
||||||
|
const categories = category.categories
|
||||||
|
if (!categories || categories.length === 0) {
|
||||||
|
return (category.entries?.length || 0) > 0
|
||||||
|
}
|
||||||
|
let hasEntries = false
|
||||||
|
for (const cat of categories) {
|
||||||
|
hasEntries = hasEntries || hasChildWithEntries(cat)
|
||||||
|
}
|
||||||
|
return hasEntries
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -9,5 +9,5 @@
|
|||||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||||
"lib": [ "ES2021.String", "dom"] /* 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", "**/**/*.test.ts", "src/pr-collector"],
|
"exclude": ["node_modules", "__tests__/*.ts", "**/*.test.ts", "**/**/*.test.ts"],
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user