Merge pull request #997 from mikepenz/feature/category_rules
Introduce `Rule` for categorisations
This commit is contained in:
@@ -219,7 +219,14 @@ This configuration is a `JSON` in the following format. (The below shocases *exa
|
|||||||
"labels": ["test", "magic"],
|
"labels": ["test", "magic"],
|
||||||
"exclude_labels": ["no-magic"],
|
"exclude_labels": ["no-magic"],
|
||||||
"exhaustive": true,
|
"exhaustive": true,
|
||||||
"empty_content": "- no matching PRs"
|
"empty_content": "- no matching PRs",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"pattern": "open",
|
||||||
|
"on_property": "status",
|
||||||
|
"flags": "gu"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ignore_labels": [
|
"ignore_labels": [
|
||||||
@@ -381,10 +388,14 @@ Table of descriptions for the `configuration.json` options to configure the resu
|
|||||||
|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| categories | An array of `category` specifications, offering a flexible way to group changes into categories. |
|
| categories | An array of `category` specifications, offering a flexible way to group changes into categories. |
|
||||||
| category.title | The display name of a category in the changelog. |
|
| category.title | The display name of a category in the changelog. |
|
||||||
| category.labels | An array of labels, to match pull request labels against. If any PR label matches any category label, the pull request will show up under this category. |
|
| category.labels | An array of labels, to match pull request labels against. If any PR label matches any category label, the pull request will show up under this category. (See `exhaustive` to change this) |
|
||||||
| category.exclude_labels | Similar to `labels`, an array of labels to match PRs against, but if a match occurs the PR is excluded from this category. |
|
| category.exclude_labels | Similar to `labels`, an array of labels to match PRs against, but if a match occurs the PR is excluded from this category. |
|
||||||
| category.exhaustive | Will require all labels defined within this category to be present on the matching PR. |
|
| category.exhaustive | Will require all labels defined within this category to be present on the matching PR. |
|
||||||
| category.empty_content | If the category has no matching PRs, this content will be used. When not set, the category will be skipped in the changelog. |
|
| category.empty_content | If the category has no matching PRs, this content will be used. When not set, the category will be skipped in the changelog. |
|
||||||
|
| category.rules | An array of `rules` used to match PRs against. Any match will include the PR. (See `exhaustive` to change this) |
|
||||||
|
| category.rules.pattern | A `regex` pattern to match the property value towards. Uses `RegExp.test("val")` |
|
||||||
|
| category.rules.flags | Defines the regex flags specified for the pattern. Default: `gu`. |
|
||||||
|
| category.rules.on_property | The PR property to match against. [Possible values](https://github.com/mikepenz/release-changelog-builder-action/blob/feature/category_rules/src/configuration.ts#L33-L43). |
|
||||||
| ignore_labels | An array of labels, to match pull request labels against. If any PR label overlaps, the pull request will be ignored from the changelog. This takes precedence over category labels |
|
| ignore_labels | An array of labels, to match pull request labels against. If any PR label overlaps, the pull request will be ignored from the changelog. This takes precedence over category labels |
|
||||||
| sort | A `sort` specification, offering the ability to define sort order and property. |
|
| sort | A `sort` specification, offering the ability to define sort order and property. |
|
||||||
| sort.order | The sort order. Allowed values: `ASC`, `DESC` |
|
| sort.order | The sort order. Allowed values: `ASC`, `DESC` |
|
||||||
@@ -397,7 +408,7 @@ Table of descriptions for the `configuration.json` options to configure the resu
|
|||||||
| label_extractor.target | The result pattern. The result text will be used as label. If empty, no label is created. (Unused for `match` method) |
|
| label_extractor.target | The result pattern. The result text will be used as label. If empty, no label is created. (Unused for `match` method) |
|
||||||
| label_extractor.on_property | The property to retrieve the text from. This is optional. Defaults to: `body`. Alternative values: `title`, `author`, `milestone`. |
|
| label_extractor.on_property | The property to retrieve the text from. This is optional. Defaults to: `body`. Alternative values: `title`, `author`, `milestone`. |
|
||||||
| label_extractor.method | The extraction method used. Defaults to: `replace`. Alternative value: `match`. The method specified references the JavaScript String method. |
|
| label_extractor.method | The extraction method used. Defaults to: `replace`. Alternative value: `match`. The method specified references the JavaScript String method. |
|
||||||
| label_extractor.flags | Defines the regex flags specified for the pattern. Default: `gu` |
|
| label_extractor.flags | Defines the regex flags specified for the pattern. Default: `gu`. |
|
||||||
| label_extractor.on_empty | Defines the placeholder to be filled in, if the regex does not lead to a result. |
|
| label_extractor.on_empty | Defines the placeholder to be filled in, if the regex does not lead to a result. |
|
||||||
| duplicate_filter | Defines the `Extractor` to use for retrieving the identifier for a PR. In case of duplicates will keep the last matching pull request (depends on `sort`). See `label_extractor` for details on `Extractor` properties. |
|
| duplicate_filter | Defines the `Extractor` to use for retrieving the identifier for a PR. In case of duplicates will keep the last matching pull request (depends on `sort`). See `label_extractor` for details on `Extractor` properties. |
|
||||||
| transformers | An array of `transform` specifications, offering a flexible API to modify the text per pull request. This is applied on the change text created with `pr_template`. `transformers` are executed per change, in the order specified |
|
| transformers | An array of `transform` specifications, offering a flexible API to modify the text per pull request. This is applied on the change text created with `pr_template`. `transformers` are executed per change, in the order specified |
|
||||||
|
|||||||
+118
-182
@@ -122,6 +122,25 @@ const pullRequestWithLabelInBody: PullRequestInfo = {
|
|||||||
status: 'merged'
|
status: 'merged'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openPullRequest: PullRequestInfo = {
|
||||||
|
number: 6,
|
||||||
|
title: 'Still pending open pull request',
|
||||||
|
htmlURL: '',
|
||||||
|
baseBranch: '',
|
||||||
|
createdAt: moment(),
|
||||||
|
mergedAt: moment(),
|
||||||
|
mergeCommitSha: 'sha1',
|
||||||
|
author: 'Mike',
|
||||||
|
repoName: 'test-repo',
|
||||||
|
labels: new Set<string>(),
|
||||||
|
milestone: '',
|
||||||
|
body: 'Some fancy body message',
|
||||||
|
assignees: [],
|
||||||
|
requestedReviewers: [],
|
||||||
|
approvedReviewers: [],
|
||||||
|
status: 'open'
|
||||||
|
}
|
||||||
|
|
||||||
it('Extract label from title, combined regex', async () => {
|
it('Extract label from title, combined regex', async () => {
|
||||||
configuration.label_extractor = [
|
configuration.label_extractor = [
|
||||||
{
|
{
|
||||||
@@ -130,22 +149,7 @@ it('Extract label from title, combined regex', async () => {
|
|||||||
on_property: 'title'
|
on_property: 'title'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
expect(buildChangelogTest(configuration, mergedPullRequests)).toStrictEqual(
|
||||||
const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
|
|
||||||
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
|
|
||||||
})
|
|
||||||
|
|
||||||
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\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`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -161,21 +165,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)
|
||||||
const resultChangelog = buildChangelog(DefaultDiffInfo, prs, {
|
expect(buildChangelogTest(configuration, prs)).toStrictEqual(
|
||||||
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
|
|
||||||
})
|
|
||||||
|
|
||||||
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`
|
`## 🚀 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`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -193,22 +183,7 @@ it('Extract label from title, split regex', async () => {
|
|||||||
on_property: 'title'
|
on_property: 'title'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
expect(buildChangelogTest(configuration, mergedPullRequests)).toStrictEqual(
|
||||||
const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
|
|
||||||
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
|
|
||||||
})
|
|
||||||
|
|
||||||
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\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`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -226,22 +201,7 @@ it('Extract label from title, match', async () => {
|
|||||||
method: 'match'
|
method: 'match'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
expect(buildChangelogTest(configuration, mergedPullRequests)).toStrictEqual(
|
||||||
const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
|
|
||||||
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
|
|
||||||
})
|
|
||||||
|
|
||||||
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\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`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -254,22 +214,7 @@ it('Extract label from title, match multiple', async () => {
|
|||||||
method: 'match'
|
method: 'match'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
expect(buildChangelogTest(configuration, mergedPullRequests)).toStrictEqual(
|
||||||
const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
|
|
||||||
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
|
|
||||||
})
|
|
||||||
|
|
||||||
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\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`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -283,22 +228,7 @@ it('Extract label from title, match multiple, custon non matching label', async
|
|||||||
on_empty: '[Other]'
|
on_empty: '[Other]'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
expect(buildChangelogTest(configuration, mergedPullRequests)).toStrictEqual(
|
||||||
const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
|
|
||||||
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
|
|
||||||
})
|
|
||||||
|
|
||||||
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\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`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -399,22 +329,7 @@ it('Match multiple labels exhaustive for category', async () => {
|
|||||||
exhaustive: true
|
exhaustive: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
expect(buildChangelogTest(customConfig, pullRequestsWithLabels)).toStrictEqual(
|
||||||
const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
|
|
||||||
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: customConfig
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(resultChangelog).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`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -426,22 +341,7 @@ it('Deduplicate duplicated PRs', async () => {
|
|||||||
on_property: 'title',
|
on_property: 'title',
|
||||||
method: 'match'
|
method: 'match'
|
||||||
}
|
}
|
||||||
|
expect(buildChangelogTest(customConfig, pullRequestsWithLabels)).toStrictEqual(
|
||||||
const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
|
|
||||||
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: customConfig
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(resultChangelog).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`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -454,22 +354,7 @@ it('Deduplicate duplicated PRs DESC', async () => {
|
|||||||
on_property: 'title',
|
on_property: 'title',
|
||||||
method: 'match'
|
method: 'match'
|
||||||
}
|
}
|
||||||
|
expect(buildChangelogTest(customConfig, pullRequestsWithLabels)).toStrictEqual(
|
||||||
const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
|
|
||||||
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: customConfig
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(resultChangelog).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`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -487,22 +372,7 @@ it('Use empty_content for empty category', async () => {
|
|||||||
labels: ['Feature']
|
labels: ['Feature']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
expect(buildChangelogTest(customConfig, pullRequestsWithLabels)).toStrictEqual(
|
||||||
const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
|
|
||||||
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: customConfig
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(resultChangelog).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`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -572,22 +442,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(
|
||||||
const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
|
|
||||||
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: customConfig
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(resultChangelog).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`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -632,7 +487,92 @@ 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}}'
|
||||||
|
|
||||||
const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
|
expect(buildChangelogTest(customConfig, mergedPullRequests)).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`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it('Use Rules to include a PR within a Category.', async () => {
|
||||||
|
const customConfig = Object.assign({}, DefaultConfiguration)
|
||||||
|
customConfig.categories = [
|
||||||
|
{
|
||||||
|
title: '## 🚀 Features But No 🐛 Fixes and only merged with a title containing `[ABC-1234]`',
|
||||||
|
labels: ['Feature'],
|
||||||
|
exclude_labels: ['Fix'],
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
pattern: "\[ABC-1234\]",
|
||||||
|
on_property: "title"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "merged",
|
||||||
|
on_property: "status"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
exhaustive: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
expect(buildChangelogTest(customConfig, pullRequestsWithLabels)).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`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Use Rules to get all open PRs in a Category.', async () => {
|
||||||
|
let prs = Array.from(pullRequestsWithLabels)
|
||||||
|
prs.push(openPullRequest)
|
||||||
|
|
||||||
|
const customConfig = Object.assign({}, DefaultConfiguration)
|
||||||
|
customConfig.categories = [
|
||||||
|
{
|
||||||
|
title: '## Open PRs only',
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
pattern: "open",
|
||||||
|
on_property: "status"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
expect(buildChangelogTest(customConfig, prs)).toStrictEqual(
|
||||||
|
`## Open PRs only\n\n- Still pending open pull request\n - PR: #6\n\n`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Use Rules to get all open PRs in one Category and merged categorised.', async () => {
|
||||||
|
let prs = Array.from(pullRequestsWithLabels)
|
||||||
|
prs.push(openPullRequest)
|
||||||
|
|
||||||
|
const customConfig = Object.assign({}, DefaultConfiguration)
|
||||||
|
customConfig.categories = [
|
||||||
|
{
|
||||||
|
title: '## Open PRs only',
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
pattern: "open",
|
||||||
|
on_property: "status"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '## 🚀 Features and 🐛 Issues',
|
||||||
|
labels: ['Feature', 'Issue'],
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
pattern: "merged",
|
||||||
|
on_property: "status"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
exhaustive: true,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
expect(buildChangelogTest(customConfig, prs)).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`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
function buildChangelogTest(config: Configuration, prs: PullRequestInfo[]): string {
|
||||||
|
return buildChangelog(DefaultDiffInfo, prs, {
|
||||||
owner: 'mikepenz',
|
owner: 'mikepenz',
|
||||||
repo: 'test-repo',
|
repo: 'test-repo',
|
||||||
fromTag: {name: '1.0.0'},
|
fromTag: {name: '1.0.0'},
|
||||||
@@ -643,10 +583,6 @@ it('Extract custom placeholder from PR body and replace in global template', asy
|
|||||||
fetchReleaseInformation: false,
|
fetchReleaseInformation: false,
|
||||||
fetchReviews: false,
|
fetchReviews: false,
|
||||||
commitMode: false,
|
commitMode: false,
|
||||||
configuration: customConfig
|
configuration: config
|
||||||
})
|
})
|
||||||
|
}
|
||||||
expect(resultChangelog).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`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
+172
-56
@@ -491,7 +491,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.compare = exports.sortPullRequests = exports.PullRequests = exports.EMPTY_COMMENT_INFO = void 0;
|
exports.retrieveProperty = exports.compare = exports.sortPullRequests = exports.PullRequests = exports.EMPTY_COMMENT_INFO = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const moment_1 = __importDefault(__nccwpck_require__(9623));
|
const moment_1 = __importDefault(__nccwpck_require__(9623));
|
||||||
exports.EMPTY_COMMENT_INFO = {
|
exports.EMPTY_COMMENT_INFO = {
|
||||||
@@ -738,6 +738,24 @@ function compare(a, b, sort) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.compare = compare;
|
exports.compare = compare;
|
||||||
|
/**
|
||||||
|
* Helper function to retrieve a property from the PullRequestInfo
|
||||||
|
*/
|
||||||
|
function retrieveProperty(pr, property, useCase) {
|
||||||
|
let value = pr[property];
|
||||||
|
if (value === undefined) {
|
||||||
|
core.warning(`⚠️ the provided property '${property}' for \`${useCase}\` is not valid. Fallback to 'body'`);
|
||||||
|
value = pr['body'];
|
||||||
|
}
|
||||||
|
else if (value instanceof Set) {
|
||||||
|
value = Array.from(value).join(','); // join into single string
|
||||||
|
}
|
||||||
|
else if (Array.isArray(value)) {
|
||||||
|
value = value.join(','); // join into single string
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
exports.retrieveProperty = retrieveProperty;
|
||||||
// helper function to add a special open label to prs not merged.
|
// helper function to add a special open label to prs not merged.
|
||||||
function attachSpeciaLabels(status, labels) {
|
function attachSpeciaLabels(status, labels) {
|
||||||
labels.add(`--rcba-${status}`);
|
labels.add(`--rcba-${status}`);
|
||||||
@@ -779,6 +797,127 @@ const mapComment = (comment) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 2364:
|
||||||
|
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
|
exports.buildRegex = exports.validateTransformer = exports.matchesRules = void 0;
|
||||||
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
|
const pullRequests_1 = __nccwpck_require__(4217);
|
||||||
|
/**
|
||||||
|
* Checks if any of the rules match the given PR
|
||||||
|
*/
|
||||||
|
function matchesRules(rules, pr, exhaustive) {
|
||||||
|
const transformers = rules.map(rule => validateTransformer(rule)).filter(t => t !== null);
|
||||||
|
if (exhaustive) {
|
||||||
|
return transformers.every(transformer => {
|
||||||
|
return matches(pr, transformer, 'rule');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return transformers.some(transformer => {
|
||||||
|
return matches(pr, transformer, 'rule');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.matchesRules = matchesRules;
|
||||||
|
/**
|
||||||
|
* Checks if the configured property results in a positive `test` with the regex.
|
||||||
|
*/
|
||||||
|
function matches(pr, extractor, extractor_usecase) {
|
||||||
|
if (extractor.pattern == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (extractor.onProperty !== undefined && extractor.onProperty.length === 1) {
|
||||||
|
const prop = extractor.onProperty[0];
|
||||||
|
const value = (0, pullRequests_1.retrieveProperty)(pr, prop, extractor_usecase);
|
||||||
|
return extractor.pattern.test(value);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function validateTransformer(transformer) {
|
||||||
|
if (transformer === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
let target = undefined;
|
||||||
|
if (transformer.hasOwnProperty('target')) {
|
||||||
|
target = transformer.target;
|
||||||
|
}
|
||||||
|
let onProperty = undefined;
|
||||||
|
let method = undefined;
|
||||||
|
let onEmpty = undefined;
|
||||||
|
if (transformer.hasOwnProperty('method')) {
|
||||||
|
method = transformer.method;
|
||||||
|
onEmpty = transformer.on_empty;
|
||||||
|
onProperty = transformer.on_property;
|
||||||
|
}
|
||||||
|
else if (transformer.hasOwnProperty('on_property')) {
|
||||||
|
onProperty = transformer.on_property;
|
||||||
|
}
|
||||||
|
// legacy handling, transform single value input to array
|
||||||
|
if (!Array.isArray(onProperty)) {
|
||||||
|
if (onProperty !== undefined) {
|
||||||
|
onProperty = [onProperty];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buildRegex(transformer, target, onProperty, method, onEmpty);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
core.warning(`⚠️ Failed to validate transformer: ${transformer.pattern}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.validateTransformer = validateTransformer;
|
||||||
|
/**
|
||||||
|
* Constructs the RegExp, providing the configured Regex and additional values
|
||||||
|
*/
|
||||||
|
function buildRegex(regex, target, onProperty, method, onEmpty) {
|
||||||
|
var _a;
|
||||||
|
try {
|
||||||
|
return {
|
||||||
|
pattern: new RegExp(regex.pattern.replace('\\\\', '\\'), (_a = regex.flags) !== null && _a !== void 0 ? _a : 'gu'),
|
||||||
|
target: target || '',
|
||||||
|
onProperty,
|
||||||
|
method,
|
||||||
|
onEmpty
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
core.warning(`⚠️ Bad replacer regex: ${regex.pattern}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.buildRegex = buildRegex;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 5882:
|
/***/ 5882:
|
||||||
@@ -1228,8 +1367,8 @@ const github = __importStar(__nccwpck_require__(5438));
|
|||||||
const semver = __importStar(__nccwpck_require__(1383));
|
const semver = __importStar(__nccwpck_require__(1383));
|
||||||
const semver_1 = __nccwpck_require__(1383);
|
const semver_1 = __nccwpck_require__(1383);
|
||||||
const gitHelper_1 = __nccwpck_require__(353);
|
const gitHelper_1 = __nccwpck_require__(353);
|
||||||
const transform_1 = __nccwpck_require__(1644);
|
|
||||||
const moment_1 = __importDefault(__nccwpck_require__(9623));
|
const moment_1 = __importDefault(__nccwpck_require__(9623));
|
||||||
|
const regexUtils_1 = __nccwpck_require__(2364);
|
||||||
class Tags {
|
class Tags {
|
||||||
constructor(octokit) {
|
constructor(octokit) {
|
||||||
this.octokit = octokit;
|
this.octokit = octokit;
|
||||||
@@ -1353,7 +1492,7 @@ class Tags {
|
|||||||
// retrieve the tags from the API
|
// retrieve the tags from the API
|
||||||
yield this.getTags(owner, repo, maxTagsToFetch), tagResolver);
|
yield this.getTags(owner, repo, maxTagsToFetch), tagResolver);
|
||||||
// check if a transformer was defined
|
// check if a transformer was defined
|
||||||
const tagTransformer = (0, transform_1.validateTransformer)(tagResolver.transformer);
|
const tagTransformer = (0, regexUtils_1.validateTransformer)(tagResolver.transformer);
|
||||||
let transformedTags;
|
let transformedTags;
|
||||||
if (tagTransformer != null) {
|
if (tagTransformer != null) {
|
||||||
core.debug(`ℹ️ Using configured tagTransformer`);
|
core.debug(`ℹ️ Using configured tagTransformer`);
|
||||||
@@ -1566,10 +1705,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.validateTransformer = exports.replaceEmptyTemplate = exports.buildChangelog = void 0;
|
exports.replaceEmptyTemplate = exports.buildChangelog = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const pullRequests_1 = __nccwpck_require__(4217);
|
const pullRequests_1 = __nccwpck_require__(4217);
|
||||||
const utils_1 = __nccwpck_require__(918);
|
const utils_1 = __nccwpck_require__(918);
|
||||||
|
const regexUtils_1 = __nccwpck_require__(2364);
|
||||||
const EMPTY_MAP = new Map();
|
const EMPTY_MAP = new Map();
|
||||||
function buildChangelog(diffInfo, prs, options) {
|
function buildChangelog(diffInfo, prs, options) {
|
||||||
// sort to target order
|
// sort to target order
|
||||||
@@ -1579,7 +1719,7 @@ function buildChangelog(diffInfo, prs, options) {
|
|||||||
core.info(`ℹ️ Sorted all pull requests ascending: ${JSON.stringify(sort)}`);
|
core.info(`ℹ️ Sorted all pull requests ascending: ${JSON.stringify(sort)}`);
|
||||||
// drop duplicate pull requests
|
// drop duplicate pull requests
|
||||||
if (config.duplicate_filter !== undefined) {
|
if (config.duplicate_filter !== undefined) {
|
||||||
const extractor = validateTransformer(config.duplicate_filter);
|
const extractor = (0, regexUtils_1.validateTransformer)(config.duplicate_filter);
|
||||||
if (extractor != null) {
|
if (extractor != null) {
|
||||||
core.info(`ℹ️ Remove duplicated pull requests using \`duplicate_filter\``);
|
core.info(`ℹ️ Remove duplicated pull requests using \`duplicate_filter\``);
|
||||||
const deduplicatedMap = new Map();
|
const deduplicatedMap = new Map();
|
||||||
@@ -1650,8 +1790,9 @@ function buildChangelog(diffInfo, prs, options) {
|
|||||||
if (pr.status === 'open') {
|
if (pr.status === 'open') {
|
||||||
openPrs.push(body);
|
openPrs.push(body);
|
||||||
}
|
}
|
||||||
let matched = false;
|
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, pullRequests] of categorized) {
|
||||||
|
let matched = false; // check if we matched within the given category
|
||||||
// check if any exclude label matches
|
// check if any exclude label matches
|
||||||
if (category.exclude_labels !== undefined) {
|
if (category.exclude_labels !== undefined) {
|
||||||
if ((0, utils_1.haveCommonElements)(category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
|
if ((0, utils_1.haveCommonElements)(category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
|
||||||
@@ -1664,23 +1805,36 @@ function buildChangelog(diffInfo, prs, options) {
|
|||||||
continue; // one of the exclude labels matched, skip the PR for this category
|
continue; // one of the exclude labels matched, skip the PR for this category
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (category.exhaustive === true) {
|
// in case we have exhaustive matching enabled, and have labels and/or rules
|
||||||
if ((0, utils_1.haveEveryElements)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
|
// validate for an exhaustive match (e.g. every provided rule applies)
|
||||||
pullRequests.push(body);
|
if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) {
|
||||||
matched = true;
|
if (category.labels !== undefined) {
|
||||||
|
matched = (0, utils_1.haveEveryElements)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels);
|
||||||
|
}
|
||||||
|
if (matched && category.rules !== undefined) {
|
||||||
|
matched = (0, regexUtils_1.matchesRules)(category.rules, pr, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ((0, utils_1.haveCommonElements)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
|
// if not exhaustive, do individual matches
|
||||||
pullRequests.push(body);
|
if (category.labels !== undefined) {
|
||||||
matched = true;
|
// check if either any of the labels applies
|
||||||
|
matched = (0, utils_1.haveCommonElements)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels);
|
||||||
|
}
|
||||||
|
if (!matched && category.rules !== undefined) {
|
||||||
|
// if no label did apply, check if any rule applies
|
||||||
|
matched = (0, regexUtils_1.matchesRules)(category.rules, pr, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (matched) {
|
||||||
|
pullRequests.push(body); // if matched add the PR to the list
|
||||||
}
|
}
|
||||||
if (!matched) {
|
matchedOnce = matchedOnce || matched;
|
||||||
|
}
|
||||||
|
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, pullRequests] of categorized) {
|
||||||
if (category.labels.length === 0) {
|
if ((category.labels === undefined || category.labels.length === 0) && category.rules === undefined) {
|
||||||
pullRequests.push(body);
|
pullRequests.push(body);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1846,7 +2000,7 @@ function handlePlaceholder(template, key, value, placeholders /* placeholders to
|
|||||||
const phs = placeholders.get(key);
|
const phs = placeholders.get(key);
|
||||||
if (phs) {
|
if (phs) {
|
||||||
for (const placeholder of phs) {
|
for (const placeholder of phs) {
|
||||||
const transformer = validateTransformer(placeholder.transformer);
|
const transformer = (0, regexUtils_1.validateTransformer)(placeholder.transformer);
|
||||||
if (transformer === null || transformer === void 0 ? void 0 : transformer.pattern) {
|
if (transformer === null || transformer === void 0 ? void 0 : transformer.pattern) {
|
||||||
const extractedValue = value.replace(transformer.pattern, transformer.target);
|
const extractedValue = value.replace(transformer.pattern, transformer.target);
|
||||||
// note: `.replace` will return the full string again if there was no match
|
// note: `.replace` will return the full string again if there was no match
|
||||||
@@ -1918,47 +2072,13 @@ function validateTransformers(specifiedTransformers) {
|
|||||||
const transformers = specifiedTransformers;
|
const transformers = specifiedTransformers;
|
||||||
return transformers
|
return transformers
|
||||||
.map(transformer => {
|
.map(transformer => {
|
||||||
return validateTransformer(transformer);
|
return (0, regexUtils_1.validateTransformer)(transformer);
|
||||||
})
|
})
|
||||||
.filter(transformer => (transformer === null || transformer === void 0 ? void 0 : transformer.pattern) != null)
|
.filter(transformer => (transformer === null || transformer === void 0 ? void 0 : transformer.pattern) != null)
|
||||||
.map(transformer => {
|
.map(transformer => {
|
||||||
return transformer;
|
return transformer;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function validateTransformer(transformer) {
|
|
||||||
var _a;
|
|
||||||
if (transformer === undefined) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
let onProperty = undefined;
|
|
||||||
let method = undefined;
|
|
||||||
let onEmpty = undefined;
|
|
||||||
if (transformer.hasOwnProperty('on_property')) {
|
|
||||||
onProperty = transformer.on_property;
|
|
||||||
method = transformer.method;
|
|
||||||
onEmpty = transformer.on_empty;
|
|
||||||
}
|
|
||||||
// legacy handling, transform single value input to array
|
|
||||||
if (!Array.isArray(onProperty)) {
|
|
||||||
if (onProperty !== undefined) {
|
|
||||||
onProperty = [onProperty];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
pattern: new RegExp(transformer.pattern.replace('\\\\', '\\'), (_a = transformer.flags) !== null && _a !== void 0 ? _a : 'gu'),
|
|
||||||
target: transformer.target || '',
|
|
||||||
onProperty,
|
|
||||||
method,
|
|
||||||
onEmpty
|
|
||||||
};
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
core.warning(`⚠️ Bad replacer regex: ${transformer.pattern}`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.validateTransformer = validateTransformer;
|
|
||||||
function extractValues(pr, extractor, extractor_usecase) {
|
function extractValues(pr, extractor, extractor_usecase) {
|
||||||
if (extractor.pattern == null) {
|
if (extractor.pattern == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -1969,11 +2089,7 @@ function extractValues(pr, extractor, extractor_usecase) {
|
|||||||
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
const prop = list[i];
|
const prop = list[i];
|
||||||
let value = pr[prop];
|
const value = (0, pullRequests_1.retrieveProperty)(pr, prop, extractor_usecase);
|
||||||
if (value === undefined) {
|
|
||||||
core.warning(`⚠️ the provided property '${extractor.onProperty}' for \`${extractor_usecase}\` is not valid`);
|
|
||||||
value = pr['body'];
|
|
||||||
}
|
|
||||||
const values = extractValuesFromString(value, extractor);
|
const values = extractValuesFromString(value, extractor);
|
||||||
if (values !== null) {
|
if (values !== null) {
|
||||||
results = results.concat(values);
|
results = results.concat(values);
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
+23
-3
@@ -20,12 +20,32 @@ export interface Configuration {
|
|||||||
|
|
||||||
export interface Category {
|
export interface Category {
|
||||||
title: string // the title of this category
|
title: string // the title of this category
|
||||||
labels: string[] // labels to associate PRs to this category
|
labels?: string[] // labels to associate PRs to this category
|
||||||
exclude_labels?: string[] // if an exclude label is detected, the PR will be excluded from this category
|
exclude_labels?: string[] // if an exclude label is detected, the PR will be excluded from this category
|
||||||
exhaustive?: boolean // requires all labels to be present in the PR
|
rules?: Rule[] // rules to associate PRs to this category
|
||||||
|
exhaustive?: boolean // requires all labels AND/OR rules to be present in the PR
|
||||||
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.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the properties of the PullRequestInfo useable in different configurations
|
||||||
|
*/
|
||||||
|
export type Property =
|
||||||
|
| 'title'
|
||||||
|
| 'branch'
|
||||||
|
| 'author'
|
||||||
|
| 'labels'
|
||||||
|
| 'milestone'
|
||||||
|
| 'body'
|
||||||
|
| 'assignees'
|
||||||
|
| 'requestedReviewers'
|
||||||
|
| 'approvedReviewers'
|
||||||
|
| 'status'
|
||||||
|
|
||||||
|
export interface Rule extends Regex {
|
||||||
|
on_property?: Property // retrieve the property to apply the rule on
|
||||||
|
}
|
||||||
|
|
||||||
export interface Sort {
|
export interface Sort {
|
||||||
order: 'ASC' | 'DESC' // the sorting order
|
order: 'ASC' | 'DESC' // the sorting order
|
||||||
on_property: 'mergedAt' | 'title' // the property to sort on. (mergedAt falls back to createdAt)
|
on_property: 'mergedAt' | 'title' // the property to sort on. (mergedAt falls back to createdAt)
|
||||||
@@ -41,7 +61,7 @@ export interface Transformer extends Regex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Extractor extends Transformer {
|
export interface Extractor extends Transformer {
|
||||||
on_property?: ('title' | 'author' | 'milestone' | 'body' | 'branch')[] | 'title' | 'author' | 'milestone' | 'body' | 'branch' | undefined // retrieve the property to extract the value from
|
on_property?: Property[] | Property | undefined // retrieve the property to extract the value from
|
||||||
method?: 'replace' | 'match' | undefined // the method to use to extract the value, `match` will not use the `target` property
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-1
@@ -2,7 +2,7 @@ import * as core from '@actions/core'
|
|||||||
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
|
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
|
||||||
import {Unpacked} from './utils'
|
import {Unpacked} from './utils'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import {Sort} from './configuration'
|
import {Property, Sort} from './configuration'
|
||||||
|
|
||||||
export interface PullRequestInfo {
|
export interface PullRequestInfo {
|
||||||
number: number
|
number: number
|
||||||
@@ -226,6 +226,22 @@ export function compare(a: PullRequestInfo, b: PullRequestInfo, sort: Sort): num
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to retrieve a property from the PullRequestInfo
|
||||||
|
*/
|
||||||
|
export function retrieveProperty(pr: PullRequestInfo, property: Property, useCase: string): string {
|
||||||
|
let value: string | Set<string> | string[] | undefined = pr[property]
|
||||||
|
if (value === undefined) {
|
||||||
|
core.warning(`⚠️ the provided property '${property}' for \`${useCase}\` is not valid. Fallback to 'body'`)
|
||||||
|
value = pr['body']
|
||||||
|
} else if (value instanceof Set) {
|
||||||
|
value = Array.from(value).join(',') // join into single string
|
||||||
|
} else if (Array.isArray(value)) {
|
||||||
|
value = value.join(',') // join into single string
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
// helper function to add a special open label to prs not merged.
|
// helper function to add a special open label to prs not merged.
|
||||||
function attachSpeciaLabels(status: 'open' | 'merged', labels: Set<string>): Set<string> {
|
function attachSpeciaLabels(status: 'open' | 'merged', labels: Set<string>): Set<string> {
|
||||||
labels.add(`--rcba-${status}`)
|
labels.add(`--rcba-${status}`)
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import * as core from '@actions/core'
|
||||||
|
import {Extractor, Property, Regex, Rule, Transformer} from './configuration'
|
||||||
|
import {PullRequestInfo, retrieveProperty} from './pullRequests'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if any of the rules match the given PR
|
||||||
|
*/
|
||||||
|
export function matchesRules(rules: Rule[], pr: PullRequestInfo, exhaustive: Boolean): boolean {
|
||||||
|
const transformers: RegexTransformer[] = rules.map(rule => validateTransformer(rule)).filter(t => t !== null) as RegexTransformer[]
|
||||||
|
if (exhaustive) {
|
||||||
|
return transformers.every(transformer => {
|
||||||
|
return matches(pr, transformer, 'rule')
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return transformers.some(transformer => {
|
||||||
|
return matches(pr, transformer, 'rule')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the configured property results in a positive `test` with the regex.
|
||||||
|
*/
|
||||||
|
function matches(pr: PullRequestInfo, extractor: RegexTransformer, extractor_usecase: string): boolean {
|
||||||
|
if (extractor.pattern == null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extractor.onProperty !== undefined && extractor.onProperty.length === 1) {
|
||||||
|
const prop = extractor.onProperty[0]
|
||||||
|
const value = retrieveProperty(pr, prop, extractor_usecase)
|
||||||
|
return extractor.pattern.test(value)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateTransformer(transformer?: Regex): RegexTransformer | null {
|
||||||
|
if (transformer === undefined) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
let target = undefined
|
||||||
|
if (transformer.hasOwnProperty('target')) {
|
||||||
|
target = (transformer as Transformer).target
|
||||||
|
}
|
||||||
|
|
||||||
|
let onProperty = undefined
|
||||||
|
let method = undefined
|
||||||
|
let onEmpty = undefined
|
||||||
|
if (transformer.hasOwnProperty('method')) {
|
||||||
|
method = (transformer as Extractor).method
|
||||||
|
onEmpty = (transformer as Extractor).on_empty
|
||||||
|
onProperty = (transformer as Extractor).on_property
|
||||||
|
} else if (transformer.hasOwnProperty('on_property')) {
|
||||||
|
onProperty = (transformer as Extractor).on_property
|
||||||
|
}
|
||||||
|
// legacy handling, transform single value input to array
|
||||||
|
if (!Array.isArray(onProperty)) {
|
||||||
|
if (onProperty !== undefined) {
|
||||||
|
onProperty = [onProperty]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildRegex(transformer, target, onProperty, method, onEmpty)
|
||||||
|
} catch (e) {
|
||||||
|
core.warning(`⚠️ Failed to validate transformer: ${transformer.pattern}`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the RegExp, providing the configured Regex and additional values
|
||||||
|
*/
|
||||||
|
export function buildRegex(
|
||||||
|
regex: Regex,
|
||||||
|
target: string | undefined,
|
||||||
|
onProperty?: Property[] | undefined,
|
||||||
|
method?: 'replace' | 'match' | undefined,
|
||||||
|
onEmpty?: string | undefined
|
||||||
|
): RegexTransformer | null {
|
||||||
|
try {
|
||||||
|
return {
|
||||||
|
pattern: new RegExp(regex.pattern.replace('\\\\', '\\'), regex.flags ?? 'gu'),
|
||||||
|
target: target || '',
|
||||||
|
onProperty,
|
||||||
|
method,
|
||||||
|
onEmpty
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
core.warning(`⚠️ Bad replacer regex: ${regex.pattern}`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RegexTransformer {
|
||||||
|
pattern: RegExp | null
|
||||||
|
target: string
|
||||||
|
onProperty?: Property[]
|
||||||
|
method?: 'replace' | 'match'
|
||||||
|
onEmpty?: string
|
||||||
|
}
|
||||||
+1
-1
@@ -5,8 +5,8 @@ import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
|
|||||||
import {SemVer} from 'semver'
|
import {SemVer} from 'semver'
|
||||||
import {TagResolver} from './configuration'
|
import {TagResolver} from './configuration'
|
||||||
import {createCommandManager} from './gitHelper'
|
import {createCommandManager} from './gitHelper'
|
||||||
import {RegexTransformer, validateTransformer} from './transform'
|
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
import {RegexTransformer, validateTransformer} from './regexUtils'
|
||||||
|
|
||||||
export interface TagResult {
|
export interface TagResult {
|
||||||
from: TagInfo | null
|
from: TagInfo | null
|
||||||
|
|||||||
+29
-66
@@ -1,17 +1,10 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {Category, Configuration, Extractor, Placeholder, Transformer} from './configuration'
|
import {Category, Configuration, Placeholder, Property, Transformer} from './configuration'
|
||||||
import {CommentInfo, EMPTY_COMMENT_INFO, PullRequestInfo, sortPullRequests} from './pullRequests'
|
import {CommentInfo, EMPTY_COMMENT_INFO, PullRequestInfo, retrieveProperty, sortPullRequests} from './pullRequests'
|
||||||
import {ReleaseNotesOptions} from './releaseNotes'
|
import {ReleaseNotesOptions} from './releaseNotes'
|
||||||
import {DiffInfo} from './commits'
|
import {DiffInfo} from './commits'
|
||||||
import {createOrSet, haveCommonElements, haveEveryElements} from './utils'
|
import {createOrSet, haveCommonElements, haveEveryElements} from './utils'
|
||||||
|
import {matchesRules, RegexTransformer, validateTransformer} from './regexUtils'
|
||||||
export interface RegexTransformer {
|
|
||||||
pattern: RegExp | null
|
|
||||||
target: string
|
|
||||||
onProperty?: ('title' | 'author' | 'milestone' | 'body' | 'status' | 'branch')[] | undefined
|
|
||||||
method?: 'replace' | 'match' | undefined
|
|
||||||
onEmpty?: string | undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
const EMPTY_MAP = new Map<string, string>()
|
const EMPTY_MAP = new Map<string, string>()
|
||||||
|
|
||||||
@@ -108,8 +101,9 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
|
|||||||
openPrs.push(body)
|
openPrs.push(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
let matched = false
|
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, pullRequests] of categorized) {
|
||||||
|
let matched = false // check if we matched within the given category
|
||||||
// check if any exclude label matches
|
// check if any exclude label matches
|
||||||
if (category.exclude_labels !== undefined) {
|
if (category.exclude_labels !== undefined) {
|
||||||
if (
|
if (
|
||||||
@@ -128,38 +122,46 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (category.exhaustive === true) {
|
// in case we have exhaustive matching enabled, and have labels and/or rules
|
||||||
if (
|
// validate for an exhaustive match (e.g. every provided rule applies)
|
||||||
haveEveryElements(
|
if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) {
|
||||||
|
if (category.labels !== undefined) {
|
||||||
|
matched = haveEveryElements(
|
||||||
category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
||||||
pr.labels
|
pr.labels
|
||||||
)
|
)
|
||||||
) {
|
}
|
||||||
pullRequests.push(body)
|
if (matched && category.rules !== undefined) {
|
||||||
matched = true
|
matched = matchesRules(category.rules, pr, true)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (
|
// if not exhaustive, do individual matches
|
||||||
haveCommonElements(
|
if (category.labels !== undefined) {
|
||||||
|
// check if either any of the labels applies
|
||||||
|
matched = haveCommonElements(
|
||||||
category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
|
||||||
pr.labels
|
pr.labels
|
||||||
)
|
)
|
||||||
) {
|
}
|
||||||
pullRequests.push(body)
|
if (!matched && category.rules !== undefined) {
|
||||||
matched = true
|
// if no label did apply, check if any rule applies
|
||||||
|
matched = matchesRules(category.rules, pr, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (matched) {
|
||||||
|
pullRequests.push(body) // if matched add the PR to the list
|
||||||
|
}
|
||||||
|
matchedOnce = matchedOnce || matched
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!matched) {
|
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, pullRequests] of categorized) {
|
||||||
if (category.labels.length === 0) {
|
if ((category.labels === undefined || category.labels.length === 0) && category.rules === undefined) {
|
||||||
pullRequests.push(body)
|
pullRequests.push(body)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uncategorizedPrs.push(body)
|
uncategorizedPrs.push(body)
|
||||||
} else {
|
} else {
|
||||||
categorizedPrs.push(body)
|
categorizedPrs.push(body)
|
||||||
@@ -458,40 +460,6 @@ function validateTransformers(specifiedTransformers: Transformer[]): RegexTransf
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validateTransformer(transformer?: Transformer): RegexTransformer | null {
|
|
||||||
if (transformer === undefined) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
let onProperty = undefined
|
|
||||||
let method = undefined
|
|
||||||
let onEmpty = undefined
|
|
||||||
if (transformer.hasOwnProperty('on_property')) {
|
|
||||||
onProperty = (transformer as Extractor).on_property
|
|
||||||
method = (transformer as Extractor).method
|
|
||||||
onEmpty = (transformer as Extractor).on_empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// legacy handling, transform single value input to array
|
|
||||||
if (!Array.isArray(onProperty)) {
|
|
||||||
if (onProperty !== undefined) {
|
|
||||||
onProperty = [onProperty]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
pattern: new RegExp(transformer.pattern.replace('\\\\', '\\'), transformer.flags ?? 'gu'),
|
|
||||||
target: transformer.target || '',
|
|
||||||
onProperty,
|
|
||||||
method,
|
|
||||||
onEmpty
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
core.warning(`⚠️ Bad replacer regex: ${transformer.pattern}`)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractValues(pr: PullRequestInfo, extractor: RegexTransformer, extractor_usecase: string): string[] | null {
|
function extractValues(pr: PullRequestInfo, extractor: RegexTransformer, extractor_usecase: string): string[] | null {
|
||||||
if (extractor.pattern == null) {
|
if (extractor.pattern == null) {
|
||||||
return null
|
return null
|
||||||
@@ -499,16 +467,11 @@ function extractValues(pr: PullRequestInfo, extractor: RegexTransformer, extract
|
|||||||
|
|
||||||
if (extractor.onProperty !== undefined) {
|
if (extractor.onProperty !== undefined) {
|
||||||
let results: string[] = []
|
let results: string[] = []
|
||||||
const list: ('title' | 'author' | 'milestone' | 'body' | 'status' | 'branch')[] = extractor.onProperty
|
const list: Property[] = extractor.onProperty
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
const prop = list[i]
|
const prop = list[i]
|
||||||
let value: string | undefined = pr[prop]
|
const value = retrieveProperty(pr, prop, extractor_usecase)
|
||||||
if (value === undefined) {
|
|
||||||
core.warning(`⚠️ the provided property '${extractor.onProperty}' for \`${extractor_usecase}\` is not valid`)
|
|
||||||
value = pr['body']
|
|
||||||
}
|
|
||||||
|
|
||||||
const values = extractValuesFromString(value, extractor)
|
const values = extractValuesFromString(value, extractor)
|
||||||
if (values !== null) {
|
if (values !== null) {
|
||||||
results = results.concat(values)
|
results = results.concat(values)
|
||||||
|
|||||||
+3
-4
@@ -2,7 +2,6 @@ import * as core from '@actions/core'
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import {Configuration, DefaultConfiguration} from './configuration'
|
import {Configuration, DefaultConfiguration} from './configuration'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the repository path, relatively to the GITHUB_WORKSPACE
|
* Resolves the repository path, relatively to the GITHUB_WORKSPACE
|
||||||
*/
|
*/
|
||||||
@@ -158,7 +157,7 @@ export function writeOutput(githubWorkspacePath: string, outputFile: string, cha
|
|||||||
|
|
||||||
export type Unpacked<T> = T extends (infer U)[] ? U : T
|
export type Unpacked<T> = T extends (infer U)[] ? U : T
|
||||||
|
|
||||||
export function createOrSet<T>(map: Map<String, T[]>, key: string, value: T): void {
|
export function createOrSet<T>(map: Map<string, T[]>, key: string, value: T): void {
|
||||||
const entry = map.get(key)
|
const entry = map.get(key)
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
map.set(key, [value])
|
map.set(key, [value])
|
||||||
@@ -167,10 +166,10 @@ export function createOrSet<T>(map: Map<String, T[]>, key: string, value: T): vo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function haveCommonElements(arr1: string[], arr2: Set<string>): Boolean {
|
export function haveCommonElements(arr1: string[], arr2: Set<string>): boolean {
|
||||||
return arr1.some(item => arr2.has(item))
|
return arr1.some(item => arr2.has(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function haveEveryElements(arr1: string[], arr2: Set<string>): Boolean {
|
export function haveEveryElements(arr1: string[], arr2: Set<string>): boolean {
|
||||||
return arr1.every(item => arr2.has(item))
|
return arr1.every(item => arr2.has(item))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
export async function wait(milliseconds: number): Promise<string> {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
if (isNaN(milliseconds)) {
|
|
||||||
throw new Error('milliseconds not a number')
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => resolve('done!'), milliseconds)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user