- introduce ability to specify on_property on extractors as Array.

- simplify setup of more complex definitions
  - FIX https://github.com/mikepenz/release-changelog-builder-action/issues/651
This commit is contained in:
Mike Penz
2022-01-28 18:17:27 +01:00
parent e0a4c3fc64
commit b5ad2456c8
6 changed files with 122 additions and 26 deletions
+3 -3
View File
@@ -340,14 +340,14 @@ Table of descriptions for the `configuration.json` options to configure the resu
# Install the dependencies # Install the dependencies
$ npm install $ npm install
# Verify lint is happy
$ npm run lint -- --fix
# Build the typescript and package it for distribution # Build the typescript and package it for distribution
$ npm run build && npm run package $ npm run build && npm run package
# Run the tests, use to debug, and test it out # Run the tests, use to debug, and test it out
$ npm test $ npm test
# Verify lint is happy
$ npm run lint -- --fix
``` ```
It's suggested to export the token to your path before running the tests so that API calls can be done to GitHub. It's suggested to export the token to your path before running the tests so that API calls can be done to GitHub.
+43
View File
@@ -90,6 +90,22 @@ mergedPullRequests.push(
} }
) )
const pullRequestWithLabelInBody: PullRequestInfo = {
number: 5,
title: 'label in body',
htmlURL: '',
baseBranch: '',
mergedAt: moment(),
mergeCommitSha: 'sha1',
author: 'Mike',
repoName: 'test-repo',
labels: new Set<string>(),
milestone: '',
body: '[Issue][Feature][AB-1234321] - no magic body for this matter',
assignees: [],
requestedReviewers: []
}
it('Extract label from title, combined regex', async () => { it('Extract label from title, combined regex', async () => {
configuration.label_extractor = [ configuration.label_extractor = [
{ {
@@ -114,6 +130,33 @@ it('Extract label from title, combined regex', async () => {
) )
}) })
it('Extract label from title and body, combined regex', async () => {
configuration.label_extractor = [
{
pattern: '.*(\\[Feature\\]|\\[Issue\\]).*',
target: '$1',
on_property: ['title', 'body']
}
]
let prs = Array.from(mergedPullRequests)
prs.push(pullRequestWithLabelInBody)
const resultChangelog = buildChangelog(prs, {
owner: 'mikepenz',
repo: 'test-repo',
fromTag: '1.0.0',
toTag: '2.0.0',
failOnError: false,
commitMode: false,
configuration
})
expect(resultChangelog).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`
)
})
it('Extract label from title, split regex', async () => { it('Extract label from title, split regex', async () => {
configuration.label_extractor = [ configuration.label_extractor = [
{ {
Generated Vendored
+29 -9
View File
@@ -1402,6 +1402,12 @@ function validateTransformer(transformer) {
method = transformer.method; method = transformer.method;
onEmpty = transformer.on_empty; onEmpty = transformer.on_empty;
} }
// legacy handling, transform single value input to array
if (!Array.isArray(onProperty)) {
if (onProperty !== undefined) {
onProperty = [onProperty];
}
}
return { return {
pattern: new RegExp(transformer.pattern.replace('\\\\', '\\'), (_a = transformer.flags) !== null && _a !== void 0 ? _a : 'gu'), pattern: new RegExp(transformer.pattern.replace('\\\\', '\\'), (_a = transformer.flags) !== null && _a !== void 0 ? _a : 'gu'),
target: transformer.target || '', target: transformer.target || '',
@@ -1420,26 +1426,40 @@ function extractValues(pr, extractor, extractor_usecase) {
if (extractor.pattern == null) { if (extractor.pattern == null) {
return null; return null;
} }
let onValue;
if (extractor.onProperty !== undefined) { if (extractor.onProperty !== undefined) {
let value = pr[extractor.onProperty]; let results = [];
if (value === undefined) { const list = extractor.onProperty;
core.warning(`⚠️ the provided property '${extractor.onProperty}' for \`${extractor_usecase}\` is not valid`); // eslint-disable-next-line @typescript-eslint/prefer-for-of
value = pr['body']; for (let i = 0; i < list.length; i++) {
const prop = list[i];
let value = pr[prop];
if (value === undefined) {
core.warning(`⚠️ the provided property '${extractor.onProperty}' for \`${extractor_usecase}\` is not valid`);
value = pr['body'];
}
const values = extractValuesFromString(value, extractor);
if (values !== null) {
results = results.concat(values);
}
} }
onValue = value; return results;
} }
else { else {
onValue = pr.body; return extractValuesFromString(pr.body, extractor);
}
}
function extractValuesFromString(value, extractor) {
if (extractor.pattern == null) {
return null;
} }
if (extractor.method === 'match') { if (extractor.method === 'match') {
const lables = onValue.match(extractor.pattern); const lables = value.match(extractor.pattern);
if (lables !== null && lables.length > 0) { if (lables !== null && lables.length > 0) {
return lables.map(label => label.toLocaleLowerCase('en')); return lables.map(label => label.toLocaleLowerCase('en'));
} }
} }
else { else {
const label = onValue.replace(extractor.pattern, extractor.target); const label = value.replace(extractor.pattern, extractor.target);
if (label !== '') { if (label !== '') {
return [label.toLocaleLowerCase('en')]; return [label.toLocaleLowerCase('en')];
} }
Generated Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
+7 -1
View File
@@ -32,7 +32,13 @@ export interface Transformer extends Regex {
} }
export interface Extractor extends Transformer { export interface Extractor extends Transformer {
on_property?: 'title' | 'author' | 'milestone' | 'body' | undefined // retrieve the property to extract the value from on_property?:
| ('title' | 'author' | 'milestone' | 'body')[]
| 'title'
| 'author'
| 'milestone'
| 'body'
| undefined // retrieve the property to extract the value from
method?: 'replace' | 'match' | undefined // the method to use to extract the value, `match` will not use the `target` property method?: 'replace' | 'match' | undefined // the method to use to extract the value, `match` will not use the `target` property
on_empty?: string | undefined // in case the regex results in an empty string, this value is gonna be used instead (only for label_extractor currently) on_empty?: string | undefined // in case the regex results in an empty string, this value is gonna be used instead (only for label_extractor currently)
} }
+39 -12
View File
@@ -309,6 +309,13 @@ export function validateTransformer(
onEmpty = (transformer as Extractor).on_empty onEmpty = (transformer as Extractor).on_empty
} }
// legacy handling, transform single value input to array
if (!Array.isArray(onProperty)) {
if (onProperty !== undefined) {
onProperty = [onProperty]
}
}
return { return {
pattern: new RegExp( pattern: new RegExp(
transformer.pattern.replace('\\\\', '\\'), transformer.pattern.replace('\\\\', '\\'),
@@ -334,27 +341,47 @@ function extractValues(
return null return null
} }
let onValue
if (extractor.onProperty !== undefined) { if (extractor.onProperty !== undefined) {
let value: string = pr[extractor.onProperty] let results: string[] = []
if (value === undefined) { const list: ('title' | 'author' | 'milestone' | 'body')[] =
core.warning( extractor.onProperty
`⚠️ the provided property '${extractor.onProperty}' for \`${extractor_usecase}\` is not valid` // eslint-disable-next-line @typescript-eslint/prefer-for-of
) for (let i = 0; i < list.length; i++) {
value = pr['body'] const prop = list[i]
let value: string = pr[prop]
if (value === undefined) {
core.warning(
`⚠️ the provided property '${extractor.onProperty}' for \`${extractor_usecase}\` is not valid`
)
value = pr['body']
}
const values = extractValuesFromString(value, extractor)
if (values !== null) {
results = results.concat(values)
}
} }
onValue = value return results
} else { } else {
onValue = pr.body return extractValuesFromString(pr.body, extractor)
}
}
function extractValuesFromString(
value: string,
extractor: RegexTransformer
): string[] | null {
if (extractor.pattern == null) {
return null
} }
if (extractor.method === 'match') { if (extractor.method === 'match') {
const lables = onValue.match(extractor.pattern) const lables = value.match(extractor.pattern)
if (lables !== null && lables.length > 0) { if (lables !== null && lables.length > 0) {
return lables.map(label => label.toLocaleLowerCase('en')) return lables.map(label => label.toLocaleLowerCase('en'))
} }
} else { } else {
const label = onValue.replace(extractor.pattern, extractor.target) const label = value.replace(extractor.pattern, extractor.target)
if (label !== '') { if (label !== '') {
return [label.toLocaleLowerCase('en')] return [label.toLocaleLowerCase('en')]
} }
@@ -368,7 +395,7 @@ function extractValues(
export interface RegexTransformer { export interface RegexTransformer {
pattern: RegExp | null pattern: RegExp | null
target: string target: string
onProperty?: 'title' | 'author' | 'milestone' | 'body' | undefined onProperty?: ('title' | 'author' | 'milestone' | 'body')[] | undefined
method?: 'replace' | 'match' | undefined method?: 'replace' | 'match' | undefined
onEmpty?: string | undefined onEmpty?: string | undefined
} }