Merge pull request #211 from mikepenz/feature/208
Allow label extraction from other fields, like the title
This commit is contained in:
@@ -167,6 +167,11 @@ This configuration is a `.json` file in the following format.
|
||||
{
|
||||
"pattern": "(.) (.+)",
|
||||
"target": "$1"
|
||||
},
|
||||
{
|
||||
"pattern": "(.) (.+)",
|
||||
"target": "$1",
|
||||
"on_property": "title"
|
||||
}
|
||||
],
|
||||
"transformers": [
|
||||
@@ -271,28 +276,29 @@ Table of supported placeholders allowed to be used in the `template` and `empty_
|
||||
|
||||
Table of descriptions for the `configuration.json` options to configure the resulting release notes / changelog.
|
||||
|
||||
| **Input** | **Description** |
|
||||
|--------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 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.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 |
|
||||
| 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 | The sort order of pull requests. [ASC, DESC] |
|
||||
| template | Specifies the global template to pick for creating the changelog. See [Template placeholders](#template-placeholders) for possible values |
|
||||
| pr_template | Defines the per pull request template. See [PR Template placeholders](#pr-template-placeholders) for possible values |
|
||||
| empty_template | Template to pick if no changes are detected. See [Template placeholders](#template-placeholders) for possible values |
|
||||
| label_extractor | An array of `transform` specifications, offering a flexible API to extract additinal labels from the body of a PR (in case of commit mode, from the commit message). |
|
||||
| label_extractor.pattern | A `regex` pattern, extracting values of the change message. |
|
||||
| label_extractor.target | The result pattern. The result text will be used as label. If empty, no label is created |
|
||||
| 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 |
|
||||
| transformer.pattern | A `regex` pattern, extracting values of the change message. |
|
||||
| transformer.target | The result pattern, the regex groups will be filled into. Allows for full transformation of a pull request message. Including potentially specified texts |
|
||||
| max_tags_to_fetch | The maximum amount of tags to load from the API to find the previous tag. Loaded paginated with 100 per page |
|
||||
| max_pull_requests | The maximum amount of pull requests to load from the API. Loaded paginated with 30 per page |
|
||||
| max_back_track_time_days | Defines the max amount of days to go back in time per changelog |
|
||||
| exclude_merge_branches | An array of branches to be ignored from processing as merge commits |
|
||||
| tag_resolver | Section to provide configuration for the tag resolving logic. Used if no `fromTag` is provided |
|
||||
| tag_resolver.method | Defines the method to use. Current options are: `semver`, `sort`. Default: `semver` |
|
||||
| **Input** | **Description** |
|
||||
|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 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.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 |
|
||||
| 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 | The sort order of pull requests. [ASC, DESC] |
|
||||
| template | Specifies the global template to pick for creating the changelog. See [Template placeholders](#template-placeholders) for possible values |
|
||||
| pr_template | Defines the per pull request template. See [PR Template placeholders](#pr-template-placeholders) for possible values |
|
||||
| empty_template | Template to pick if no changes are detected. See [Template placeholders](#template-placeholders) for possible values |
|
||||
| label_extractor | An array of `transform` specifications, offering a flexible API to extract additinal labels from a PR (Default: `body`, Default in commit mode: `commit message`). |
|
||||
| label_extractor.pattern | A `regex` pattern, extracting values of the change message. |
|
||||
| label_extractor.target | The result pattern. The result text will be used as label. If empty, no label is created. |
|
||||
| label_extractor.on_property | The property to retrieve the text from. This is optional. Defaults to: `body`. Alternative values: `title`, `author`, `milestone`. |
|
||||
| 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 |
|
||||
| transformer.pattern | A `regex` pattern, extracting values of the change message. |
|
||||
| transformer.target | The result pattern, the regex groups will be filled into. Allows for full transformation of a pull request message. Including potentially specified texts |
|
||||
| max_tags_to_fetch | The maximum amount of tags to load from the API to find the previous tag. Loaded paginated with 100 per page |
|
||||
| max_pull_requests | The maximum amount of pull requests to load from the API. Loaded paginated with 30 per page |
|
||||
| max_back_track_time_days | Defines the max amount of days to go back in time per changelog |
|
||||
| exclude_merge_branches | An array of branches to be ignored from processing as merge commits |
|
||||
| tag_resolver | Section to provide configuration for the tag resolving logic. Used if no `fromTag` is provided |
|
||||
| tag_resolver.method | Defines the method to use. Current options are: `semver`, `sort`. Default: `semver` |
|
||||
|
||||
## Contribute 🧬
|
||||
|
||||
|
||||
+35
-6
@@ -1074,7 +1074,18 @@ function buildChangelog(prs, config, options) {
|
||||
for (const extractor of labelExtractors) {
|
||||
if (extractor.pattern != null) {
|
||||
for (const pr of prs) {
|
||||
const label = pr.body.replace(extractor.pattern, extractor.target);
|
||||
let label;
|
||||
if (extractor.onProperty !== undefined) {
|
||||
let value = pr[extractor.onProperty];
|
||||
if (value === undefined) {
|
||||
core.warning(`⚠️ the provided property '${extractor.onProperty}' for \`label_extractor\` is not valid`);
|
||||
value = pr['body'];
|
||||
}
|
||||
label = value.replace(extractor.pattern, extractor.target);
|
||||
}
|
||||
else {
|
||||
label = pr.body.replace(extractor.pattern, extractor.target);
|
||||
}
|
||||
if (label !== '') {
|
||||
pr.labels.push(label);
|
||||
}
|
||||
@@ -1208,16 +1219,22 @@ function validateTransfomers(specifiedTransformers) {
|
||||
return transformers
|
||||
.map(transformer => {
|
||||
try {
|
||||
let onProperty = undefined;
|
||||
if (transformer.hasOwnProperty('on_property')) {
|
||||
onProperty = transformer.on_property;
|
||||
}
|
||||
return {
|
||||
pattern: new RegExp(transformer.pattern.replace('\\\\', '\\'), 'gu'),
|
||||
target: transformer.target
|
||||
target: transformer.target,
|
||||
onProperty
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
core.warning(`⚠️ Bad replacer regex: ${transformer.pattern}`);
|
||||
return {
|
||||
pattern: null,
|
||||
target: ''
|
||||
target: '',
|
||||
onProperty: undefined
|
||||
};
|
||||
}
|
||||
})
|
||||
@@ -4685,6 +4702,7 @@ const Endpoints = {
|
||||
actions: {
|
||||
addSelectedRepoToOrgSecret: ["PUT /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}"],
|
||||
cancelWorkflowRun: ["POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel"],
|
||||
createOrUpdateEnvironmentSecret: ["PUT /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}"],
|
||||
createOrUpdateOrgSecret: ["PUT /orgs/{org}/actions/secrets/{secret_name}"],
|
||||
createOrUpdateRepoSecret: ["PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}"],
|
||||
createRegistrationTokenForOrg: ["POST /orgs/{org}/actions/runners/registration-token"],
|
||||
@@ -4693,6 +4711,7 @@ const Endpoints = {
|
||||
createRemoveTokenForRepo: ["POST /repos/{owner}/{repo}/actions/runners/remove-token"],
|
||||
createWorkflowDispatch: ["POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches"],
|
||||
deleteArtifact: ["DELETE /repos/{owner}/{repo}/actions/artifacts/{artifact_id}"],
|
||||
deleteEnvironmentSecret: ["DELETE /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}"],
|
||||
deleteOrgSecret: ["DELETE /orgs/{org}/actions/secrets/{secret_name}"],
|
||||
deleteRepoSecret: ["DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}"],
|
||||
deleteSelfHostedRunnerFromOrg: ["DELETE /orgs/{org}/actions/runners/{runner_id}"],
|
||||
@@ -4709,16 +4728,20 @@ const Endpoints = {
|
||||
getAllowedActionsOrganization: ["GET /orgs/{org}/actions/permissions/selected-actions"],
|
||||
getAllowedActionsRepository: ["GET /repos/{owner}/{repo}/actions/permissions/selected-actions"],
|
||||
getArtifact: ["GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}"],
|
||||
getEnvironmentPublicKey: ["GET /repositories/{repository_id}/environments/{environment_name}/secrets/public-key"],
|
||||
getEnvironmentSecret: ["GET /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}"],
|
||||
getGithubActionsPermissionsOrganization: ["GET /orgs/{org}/actions/permissions"],
|
||||
getGithubActionsPermissionsRepository: ["GET /repos/{owner}/{repo}/actions/permissions"],
|
||||
getJobForWorkflowRun: ["GET /repos/{owner}/{repo}/actions/jobs/{job_id}"],
|
||||
getOrgPublicKey: ["GET /orgs/{org}/actions/secrets/public-key"],
|
||||
getOrgSecret: ["GET /orgs/{org}/actions/secrets/{secret_name}"],
|
||||
getPendingDeploymentsForRun: ["GET /repos/{owner}/{repo}/actions/runs/{run_id}/pending_deployments"],
|
||||
getRepoPermissions: ["GET /repos/{owner}/{repo}/actions/permissions", {}, {
|
||||
renamed: ["actions", "getGithubActionsPermissionsRepository"]
|
||||
}],
|
||||
getRepoPublicKey: ["GET /repos/{owner}/{repo}/actions/secrets/public-key"],
|
||||
getRepoSecret: ["GET /repos/{owner}/{repo}/actions/secrets/{secret_name}"],
|
||||
getReviewsForRun: ["GET /repos/{owner}/{repo}/actions/runs/{run_id}/approvals"],
|
||||
getSelfHostedRunnerForOrg: ["GET /orgs/{org}/actions/runners/{runner_id}"],
|
||||
getSelfHostedRunnerForRepo: ["GET /repos/{owner}/{repo}/actions/runners/{runner_id}"],
|
||||
getWorkflow: ["GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}"],
|
||||
@@ -4726,6 +4749,7 @@ const Endpoints = {
|
||||
getWorkflowRunUsage: ["GET /repos/{owner}/{repo}/actions/runs/{run_id}/timing"],
|
||||
getWorkflowUsage: ["GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/timing"],
|
||||
listArtifactsForRepo: ["GET /repos/{owner}/{repo}/actions/artifacts"],
|
||||
listEnvironmentSecrets: ["GET /repositories/{repository_id}/environments/{environment_name}/secrets"],
|
||||
listJobsForWorkflowRun: ["GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs"],
|
||||
listOrgSecrets: ["GET /orgs/{org}/actions/secrets"],
|
||||
listRepoSecrets: ["GET /repos/{owner}/{repo}/actions/secrets"],
|
||||
@@ -4741,6 +4765,7 @@ const Endpoints = {
|
||||
listWorkflowRunsForRepo: ["GET /repos/{owner}/{repo}/actions/runs"],
|
||||
reRunWorkflow: ["POST /repos/{owner}/{repo}/actions/runs/{run_id}/rerun"],
|
||||
removeSelectedRepoFromOrgSecret: ["DELETE /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}"],
|
||||
reviewPendingDeploymentsForRun: ["POST /repos/{owner}/{repo}/actions/runs/{run_id}/pending_deployments"],
|
||||
setAllowedActionsOrganization: ["PUT /orgs/{org}/actions/permissions/selected-actions"],
|
||||
setAllowedActionsRepository: ["PUT /repos/{owner}/{repo}/actions/permissions/selected-actions"],
|
||||
setGithubActionsPermissionsOrganization: ["PUT /orgs/{org}/actions/permissions"],
|
||||
@@ -5373,7 +5398,7 @@ const Endpoints = {
|
||||
previews: ["squirrel-girl"]
|
||||
}
|
||||
}, {
|
||||
deprecated: "octokit.reactions.deleteLegacy() is deprecated, see https://docs.github.com/v3/reactions/#delete-a-reaction-legacy"
|
||||
deprecated: "octokit.reactions.deleteLegacy() is deprecated, see https://docs.github.com/rest/reference/reactions/#delete-a-reaction-legacy"
|
||||
}],
|
||||
listForCommitComment: ["GET /repos/{owner}/{repo}/comments/{comment_id}/reactions", {
|
||||
mediaType: {
|
||||
@@ -5442,6 +5467,7 @@ const Endpoints = {
|
||||
createForAuthenticatedUser: ["POST /user/repos"],
|
||||
createFork: ["POST /repos/{owner}/{repo}/forks"],
|
||||
createInOrg: ["POST /orgs/{org}/repos"],
|
||||
createOrUpdateEnvironment: ["PUT /repos/{owner}/{repo}/environments/{environment_name}"],
|
||||
createOrUpdateFileContents: ["PUT /repos/{owner}/{repo}/contents/{path}"],
|
||||
createPagesSite: ["POST /repos/{owner}/{repo}/pages", {
|
||||
mediaType: {
|
||||
@@ -5459,6 +5485,7 @@ const Endpoints = {
|
||||
delete: ["DELETE /repos/{owner}/{repo}"],
|
||||
deleteAccessRestrictions: ["DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions"],
|
||||
deleteAdminBranchProtection: ["DELETE /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins"],
|
||||
deleteAnEnvironment: ["DELETE /repos/{owner}/{repo}/environments/{environment_name}"],
|
||||
deleteBranchProtection: ["DELETE /repos/{owner}/{repo}/branches/{branch}/protection"],
|
||||
deleteCommitComment: ["DELETE /repos/{owner}/{repo}/comments/{comment_id}"],
|
||||
deleteCommitSignatureProtection: ["DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures", {
|
||||
@@ -5507,6 +5534,7 @@ const Endpoints = {
|
||||
get: ["GET /repos/{owner}/{repo}"],
|
||||
getAccessRestrictions: ["GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions"],
|
||||
getAdminBranchProtection: ["GET /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins"],
|
||||
getAllEnvironments: ["GET /repos/{owner}/{repo}/environments"],
|
||||
getAllStatusCheckContexts: ["GET /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts"],
|
||||
getAllTopics: ["GET /repos/{owner}/{repo}/topics", {
|
||||
mediaType: {
|
||||
@@ -5534,6 +5562,7 @@ const Endpoints = {
|
||||
getDeployKey: ["GET /repos/{owner}/{repo}/keys/{key_id}"],
|
||||
getDeployment: ["GET /repos/{owner}/{repo}/deployments/{deployment_id}"],
|
||||
getDeploymentStatus: ["GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses/{status_id}"],
|
||||
getEnvironment: ["GET /repos/{owner}/{repo}/environments/{environment_name}"],
|
||||
getLatestPagesBuild: ["GET /repos/{owner}/{repo}/pages/builds/latest"],
|
||||
getLatestRelease: ["GET /repos/{owner}/{repo}/releases/latest"],
|
||||
getPages: ["GET /repos/{owner}/{repo}/pages"],
|
||||
@@ -5745,7 +5774,7 @@ const Endpoints = {
|
||||
}
|
||||
};
|
||||
|
||||
const VERSION = "4.12.2";
|
||||
const VERSION = "4.13.2";
|
||||
|
||||
function endpointsToMethods(octokit, endpointsMap) {
|
||||
const newMethods = {};
|
||||
@@ -6071,7 +6100,7 @@ var pluginRequestLog = __nccwpck_require__(8883);
|
||||
var pluginPaginateRest = __nccwpck_require__(4193);
|
||||
var pluginRestEndpointMethods = __nccwpck_require__(3044);
|
||||
|
||||
const VERSION = "18.2.1";
|
||||
const VERSION = "18.3.2";
|
||||
|
||||
const Octokit = core.Octokit.plugin(pluginRequestLog.requestLog, pluginRestEndpointMethods.restEndpointMethods, pluginPaginateRest.paginateRest).defaults({
|
||||
userAgent: `octokit-rest.js/${VERSION}`
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -9,7 +9,7 @@ export interface Configuration {
|
||||
empty_template: string
|
||||
categories: Category[]
|
||||
ignore_labels: string[]
|
||||
label_extractor: Transformer[]
|
||||
label_extractor: Extractor[]
|
||||
transformers: Transformer[]
|
||||
tag_resolver: TagResolver
|
||||
}
|
||||
@@ -24,6 +24,10 @@ export interface Transformer {
|
||||
target: string
|
||||
}
|
||||
|
||||
export interface Extractor extends Transformer {
|
||||
on_property: 'title' | 'author' | 'milestone' | 'body' | undefined
|
||||
}
|
||||
|
||||
export interface TagResolver {
|
||||
method: string // semver, sort
|
||||
}
|
||||
|
||||
+24
-3
@@ -2,6 +2,7 @@ import {PullRequestInfo, sortPullRequests} from './pullRequests'
|
||||
import * as core from '@actions/core'
|
||||
import {ReleaseNotesOptions} from './releaseNotes'
|
||||
import {
|
||||
Extractor,
|
||||
Category,
|
||||
Configuration,
|
||||
Transformer,
|
||||
@@ -24,7 +25,19 @@ export function buildChangelog(
|
||||
for (const extractor of labelExtractors) {
|
||||
if (extractor.pattern != null) {
|
||||
for (const pr of prs) {
|
||||
const label = pr.body.replace(extractor.pattern, extractor.target)
|
||||
let label
|
||||
if (extractor.onProperty !== undefined) {
|
||||
let value: string = pr[extractor.onProperty]
|
||||
if (value === undefined) {
|
||||
core.warning(
|
||||
`⚠️ the provided property '${extractor.onProperty}' for \`label_extractor\` is not valid`
|
||||
)
|
||||
value = pr['body']
|
||||
}
|
||||
label = value.replace(extractor.pattern, extractor.target)
|
||||
} else {
|
||||
label = pr.body.replace(extractor.pattern, extractor.target)
|
||||
}
|
||||
if (label !== '') {
|
||||
pr.labels.push(label)
|
||||
}
|
||||
@@ -222,15 +235,22 @@ function validateTransfomers(
|
||||
return transformers
|
||||
.map(transformer => {
|
||||
try {
|
||||
let onProperty = undefined
|
||||
if (transformer.hasOwnProperty('on_property')) {
|
||||
onProperty = (transformer as Extractor).on_property
|
||||
}
|
||||
|
||||
return {
|
||||
pattern: new RegExp(transformer.pattern.replace('\\\\', '\\'), 'gu'),
|
||||
target: transformer.target
|
||||
target: transformer.target,
|
||||
onProperty
|
||||
}
|
||||
} catch (e) {
|
||||
core.warning(`⚠️ Bad replacer regex: ${transformer.pattern}`)
|
||||
return {
|
||||
pattern: null,
|
||||
target: ''
|
||||
target: '',
|
||||
onProperty: undefined
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -240,4 +260,5 @@ function validateTransfomers(
|
||||
interface RegexTransformer {
|
||||
pattern: RegExp | null
|
||||
target: string
|
||||
onProperty: 'title' | 'author' | 'milestone' | 'body' | undefined
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user