- introduce capability for custom placeholders also to the global template

- introduce new convenient functions to handle this
This commit is contained in:
Mike Penz
2022-07-29 14:54:45 +00:00
committed by GitHub
parent 15a108d43e
commit 7b1021454a
7 changed files with 159 additions and 110 deletions
+1 -1
View File
@@ -366,7 +366,7 @@ Table of supported placeholders allowed to be used in the `template` and `empty_
| `${{UNCATEGORIZED_COUNT}}` | The count of PRs and changes which were not categorized. No label overlapping with category labels | | | `${{UNCATEGORIZED_COUNT}}` | The count of PRs and changes which were not categorized. No label overlapping with category labels | |
| `${{OPEN_COUNT}}` | The count of open PRs. Will only be fetched if `includeOpen` is configured. | | | `${{OPEN_COUNT}}` | The count of open PRs. Will only be fetched if `includeOpen` is configured. | |
| `${{IGNORED_COUNT}}` | The count of PRs and changes which were specifically ignored from the changelog. | | | `${{IGNORED_COUNT}}` | The count of PRs and changes which were specifically ignored from the changelog. | |
| `${{DAYS_SINCE}}` | Days between the 2 releases. Requires `fetchReleaseInformation` to be enabled. | * | | `${{DAYS_SINCE}}` | Days between the 2 releases. Requires `fetchReleaseInformation` to be enabled. | x |
### Configuration Specification ### Configuration Specification
-2
View File
@@ -1,5 +1,3 @@
import {resolveConfiguration} from '../src/utils'
import {ReleaseNotesBuilder} from '../src/releaseNotesBuilder'
import { TagInfo, sortTags, filterTags } from '../src/tags'; import { TagInfo, sortTags, filterTags } from '../src/tags';
jest.setTimeout(180000) jest.setTimeout(180000)
+1 -1
View File
@@ -1,7 +1,7 @@
import {buildChangelog} from '../src/transform' import {buildChangelog} from '../src/transform'
import {PullRequestInfo} from '../src/pullRequests' import {PullRequestInfo} from '../src/pullRequests'
import moment from 'moment' import moment from 'moment'
import { DefaultConfiguration, Configuration } from '../src/configuration'; import { DefaultConfiguration } from '../src/configuration';
import { DefaultDiffInfo } from '../src/commits'; import { DefaultDiffInfo } from '../src/commits';
jest.setTimeout(180000) jest.setTimeout(180000)
Generated Vendored
+88 -53
View File
@@ -217,7 +217,8 @@ exports.DefaultConfiguration = {
filter: undefined, filter: undefined,
transformer: undefined // transforms the tag name using the regex, run after the filter transformer: undefined // transforms the tag name using the regex, run after the filter
}, },
base_branches: [] // target branches for the merged PR ignoring PRs with different target branch, by default it will get all PRs base_branches: [],
custom_placeholders: []
}; };
@@ -782,7 +783,7 @@ class ReleaseNotes {
core.setOutput('commits', diffInfo.commits); core.setOutput('commits', diffInfo.commits);
if (mergedPullRequests.length === 0) { if (mergedPullRequests.length === 0) {
core.warning(`⚠️ No pull requests found`); core.warning(`⚠️ No pull requests found`);
return (0, transform_1.fillAdditionalPlaceholders)(this.options.configuration.empty_template || configuration_1.DefaultConfiguration.empty_template, this.options); return (0, transform_1.replaceEmptyTemplate)(this.options.configuration.empty_template || configuration_1.DefaultConfiguration.empty_template, this.options);
} }
core.startGroup('📦 Build changelog'); core.startGroup('📦 Build changelog');
const resultChangelog = (0, transform_1.buildChangelog)(diffInfo, mergedPullRequests, this.options); const resultChangelog = (0, transform_1.buildChangelog)(diffInfo, mergedPullRequests, this.options);
@@ -1444,7 +1445,7 @@ 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.fillAdditionalPlaceholders = exports.buildChangelog = void 0; exports.validateTransformer = exports.replaceEmptyTemplate = exports.buildChangelog = void 0;
const core = __importStar(__nccwpck_require__(2186)); const core = __importStar(__nccwpck_require__(2186));
const configuration_1 = __nccwpck_require__(5527); const configuration_1 = __nccwpck_require__(5527);
const pullRequests_1 = __nccwpck_require__(4217); const pullRequests_1 = __nccwpck_require__(4217);
@@ -1493,11 +1494,15 @@ function buildChangelog(diffInfo, prs, options) {
} }
} }
} }
const placeholders = new Map();
for (const ph of config.custom_placeholders || []) {
placeholders.set(ph.source, ph);
}
const validatedTransformers = validateTransformers(config.transformers); const validatedTransformers = validateTransformers(config.transformers);
const transformedMap = new Map(); const transformedMap = new Map();
// convert PRs to their text representation // convert PRs to their text representation
for (const pr of prs) { for (const pr of prs) {
transformedMap.set(pr, transform(fillTemplate(pr, config.pr_template || configuration_1.DefaultConfiguration.pr_template), validatedTransformers)); transformedMap.set(pr, transform(fillTemplate(pr, config.pr_template || configuration_1.DefaultConfiguration.pr_template, placeholders), validatedTransformers));
} }
core.info(`️ Used ${validatedTransformers.length} transformers to adjust message`); core.info(`️ Used ${validatedTransformers.length} transformers to adjust message`);
core.info(`✒️ Wrote messages for ${prs.length} pull requests`); core.info(`✒️ Wrote messages for ${prs.length} pull requests`);
@@ -1620,74 +1625,98 @@ function buildChangelog(diffInfo, prs, options) {
} }
core.info(`✒️ Wrote ${ignoredPrs.length} ignored pull requests down`); core.info(`✒️ Wrote ${ignoredPrs.length} ignored pull requests down`);
// fill template // fill template
let transformedChangelog = config.template || configuration_1.DefaultConfiguration.template; const placeholderMap = new Map();
transformedChangelog = transformedChangelog.replace(/\${{CHANGELOG}}/g, changelog); placeholderMap.set('CHANGELOG', changelog);
transformedChangelog = transformedChangelog.replace(/\${{UNCATEGORIZED}}/g, changelogUncategorized); placeholderMap.set('UNCATEGORIZED', changelogUncategorized);
transformedChangelog = transformedChangelog.replace(/\${{OPEN}}/g, changelogOpen); placeholderMap.set('OPEN', changelogOpen);
transformedChangelog = transformedChangelog.replace(/\${{IGNORED}}/g, changelogIgnored); placeholderMap.set('IGNORED', changelogIgnored);
// fill other placeholders // fill other placeholders
transformedChangelog = transformedChangelog.replace(/\${{CATEGORIZED_COUNT}}/g, categorizedPrs.length.toString()); placeholderMap.set('CATEGORIZED_COUNT', categorizedPrs.length.toString());
transformedChangelog = transformedChangelog.replace(/\${{UNCATEGORIZED_COUNT}}/g, uncategorizedPrs.length.toString()); placeholderMap.set('UNCATEGORIZED_COUNT', uncategorizedPrs.length.toString());
transformedChangelog = transformedChangelog.replace(/\${{OPEN_COUNT}}/g, openPrs.length.toString()); placeholderMap.set('OPEN_COUNT', openPrs.length.toString());
transformedChangelog = transformedChangelog.replace(/\${{IGNORED_COUNT}}/g, ignoredPrs.length.toString()); placeholderMap.set('IGNORED_COUNT', ignoredPrs.length.toString());
// code change placeholders // code change placeholders
transformedChangelog = transformedChangelog.replace(/\${{CHANGED_FILES}}/g, diffInfo.changedFiles.toString()); placeholderMap.set('CHANGED_FILES', diffInfo.changedFiles.toString());
transformedChangelog = transformedChangelog.replace(/\${{ADDITIONS}}/g, diffInfo.additions.toString()); placeholderMap.set('ADDITIONS', diffInfo.additions.toString());
transformedChangelog = transformedChangelog.replace(/\${{DELETIONS}}/g, diffInfo.deletions.toString()); placeholderMap.set('DELETIONS', diffInfo.deletions.toString());
transformedChangelog = transformedChangelog.replace(/\${{CHANGES}}/g, diffInfo.changes.toString()); placeholderMap.set('CHANGES', diffInfo.changes.toString());
transformedChangelog = transformedChangelog.replace(/\${{COMMITS}}/g, diffInfo.commits.toString()); placeholderMap.set('COMMITS', diffInfo.commits.toString());
transformedChangelog = fillAdditionalPlaceholders(transformedChangelog, options); fillAdditionalPlaceholders(options, placeholderMap);
let transformedChangelog = config.template || configuration_1.DefaultConfiguration.template;
transformedChangelog = replacePlaceHolders(transformedChangelog, placeholderMap, placeholders);
core.info(`️ Filled template`); core.info(`️ Filled template`);
return transformedChangelog; return transformedChangelog;
} }
exports.buildChangelog = buildChangelog; exports.buildChangelog = buildChangelog;
function fillAdditionalPlaceholders(text, options) { function replaceEmptyTemplate(template, options) {
const placeholders = new Map();
for (const ph of options.configuration.custom_placeholders || []) {
placeholders.set(ph.source, ph);
}
const placeholderMap = new Map();
fillAdditionalPlaceholders(options, placeholderMap);
return replacePlaceHolders(template, placeholderMap, placeholders);
}
exports.replaceEmptyTemplate = replaceEmptyTemplate;
function fillAdditionalPlaceholders(options, placeholderMap) {
var _a, _b; var _a, _b;
let transformed = text;
// repository placeholders // repository placeholders
transformed = transformed.replace(/\${{OWNER}}/g, options.owner); placeholderMap.set('OWNER', options.owner);
transformed = transformed.replace(/\${{REPO}}/g, options.repo); placeholderMap.set('REPO', options.repo);
transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag.name); placeholderMap.set('FROM_TAG', options.fromTag.name);
transformed = transformed.replace(/\${{FROM_TAG_DATE}}/g, ((_a = options.fromTag.date) === null || _a === void 0 ? void 0 : _a.toISOString()) || ''); placeholderMap.set('FROM_TAG_DATE', ((_a = options.fromTag.date) === null || _a === void 0 ? void 0 : _a.toISOString()) || '');
transformed = transformed.replace(/\${{TO_TAG}}/g, options.toTag.name); placeholderMap.set('TO_TAG', options.toTag.name);
transformed = transformed.replace(/\${{TO_TAG_DATE}}/g, ((_b = options.toTag.date) === null || _b === void 0 ? void 0 : _b.toISOString()) || ''); placeholderMap.set('TO_TAG_DATE', ((_b = options.toTag.date) === null || _b === void 0 ? void 0 : _b.toISOString()) || '');
const fromDate = options.fromTag.date; const fromDate = options.fromTag.date;
const toDate = options.toTag.date; const toDate = options.toTag.date;
if (fromDate !== undefined && toDate !== undefined) { if (fromDate !== undefined && toDate !== undefined) {
transformed = transformed.replace(/\${{DAYS_SINCE}}/g, toDate.diff(fromDate, 'days').toString() || ''); placeholderMap.set('DAYS_SINCE', toDate.diff(fromDate, 'days').toString() || '');
} }
else { else {
transformed = transformed.replace(/\${{DAYS_SINCE}}/g, ''); placeholderMap.set('DAYS_SINCE', '');
} }
transformed = transformed.replace(/\${{RELEASE_DIFF}}/g, `https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag.name}...${options.toTag.name}`); placeholderMap.set('RELEASE_DIFF', `https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag.name}...${options.toTag.name}`);
return transformed;
} }
exports.fillAdditionalPlaceholders = fillAdditionalPlaceholders; function fillTemplate(pr, template, placeholders) {
function haveCommonElements(arr1, arr2) {
return arr1.some(item => arr2.has(item));
}
function haveEveryElements(arr1, arr2) {
return arr1.every(item => arr2.has(item));
}
function fillTemplate(pr, template) {
var _a, _b, _c, _d, _e, _f; var _a, _b, _c, _d, _e, _f;
const placeholderMap = new Map();
placeholderMap.set('NUMBER', pr.number.toString());
placeholderMap.set('TITLE', pr.title);
placeholderMap.set('URL', pr.htmlURL);
placeholderMap.set('STATUS', pr.status);
placeholderMap.set('CREATED_AT', pr.createdAt.toISOString());
placeholderMap.set('MERGED_AT', ((_a = pr.mergedAt) === null || _a === void 0 ? void 0 : _a.toISOString()) || '');
placeholderMap.set('MERGE_SHA', pr.mergeCommitSha);
placeholderMap.set('AUTHOR', pr.author);
placeholderMap.set('LABELS', ((_c = (_b = [...pr.labels]) === null || _b === void 0 ? void 0 : _b.filter(l => !l.startsWith('--rcba-'))) === null || _c === void 0 ? void 0 : _c.join(', ')) || '');
placeholderMap.set('MILESTONE', pr.milestone || '');
placeholderMap.set('BODY', pr.body);
placeholderMap.set('ASSIGNEES', ((_d = pr.assignees) === null || _d === void 0 ? void 0 : _d.join(', ')) || '');
placeholderMap.set('REVIEWERS', ((_e = pr.requestedReviewers) === null || _e === void 0 ? void 0 : _e.join(', ')) || '');
placeholderMap.set('APPROVERS', ((_f = pr.approvedReviewers) === null || _f === void 0 ? void 0 : _f.join(', ')) || '');
placeholderMap.set('BRANCH', pr.branch || '');
placeholderMap.set('BASE_BRANCH', pr.baseBranch);
return replacePlaceHolders(template, placeholderMap, placeholders);
}
function replacePlaceHolders(template, placeholderMap, placeholders) {
let transformed = template; let transformed = template;
transformed = transformed.replace(/\${{NUMBER}}/g, pr.number.toString()); for (const [key, value] of placeholderMap) {
transformed = transformed.replace(/\${{TITLE}}/g, pr.title); transformed = transformed.replaceAll(`\${{${key}}}`, value);
transformed = transformed.replace(/\${{URL}}/g, pr.htmlURL); // replace custom placeholders
transformed = transformed.replace(/\${{STATUS}}/g, pr.status); transformed = applyCustomPlaceholder(transformed, value, placeholders.get(key));
transformed = transformed.replace(/\${{CREATED_AT}}/g, pr.createdAt.toISOString()); }
transformed = transformed.replace(/\${{MERGED_AT}}/g, ((_a = pr.mergedAt) === null || _a === void 0 ? void 0 : _a.toISOString()) || '');
transformed = transformed.replace(/\${{MERGE_SHA}}/g, pr.mergeCommitSha);
transformed = transformed.replace(/\${{AUTHOR}}/g, pr.author);
transformed = transformed.replace(/\${{LABELS}}/g, ((_c = (_b = [...pr.labels]) === null || _b === void 0 ? void 0 : _b.filter(l => !l.startsWith('--rcba-'))) === null || _c === void 0 ? void 0 : _c.join(', ')) || '');
transformed = transformed.replace(/\${{MILESTONE}}/g, pr.milestone || '');
transformed = transformed.replace(/\${{BODY}}/g, pr.body);
transformed = transformed.replace(/\${{ASSIGNEES}}/g, ((_d = pr.assignees) === null || _d === void 0 ? void 0 : _d.join(', ')) || '');
transformed = transformed.replace(/\${{REVIEWERS}}/g, ((_e = pr.requestedReviewers) === null || _e === void 0 ? void 0 : _e.join(', ')) || '');
transformed = transformed.replace(/\${{APPROVERS}}/g, ((_f = pr.approvedReviewers) === null || _f === void 0 ? void 0 : _f.join(', ')) || '');
return transformed; return transformed;
} }
function applyCustomPlaceholder(template, value, placeholder) {
if (placeholder) {
const transformer = validateTransformer(placeholder.transformer);
if (transformer === null || transformer === void 0 ? void 0 : transformer.pattern) {
const extractedValue = value.replace(transformer.pattern, transformer.target);
return template.replaceAll(`\${{${placeholder.name}}}`, extractedValue);
}
}
return template;
}
function transform(filled, transformers) { function transform(filled, transformers) {
if (transformers.length === 0) { if (transformers.length === 0) {
return filled; return filled;
@@ -1792,6 +1821,12 @@ function extractValuesFromString(value, extractor) {
} }
return null; return null;
} }
function haveCommonElements(arr1, arr2) {
return arr1.some(item => arr2.has(item));
}
function haveEveryElements(arr1, arr2) {
return arr1.every(item => arr2.has(item));
}
/***/ }), /***/ }),
Generated Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -3,7 +3,7 @@ import {Commits, filterCommits, DiffInfo, DefaultDiffInfo} from './commits'
import {Configuration, DefaultConfiguration} from './configuration' import {Configuration, DefaultConfiguration} from './configuration'
import {PullRequestInfo, PullRequests} from './pullRequests' import {PullRequestInfo, PullRequests} from './pullRequests'
import {Octokit} from '@octokit/rest' import {Octokit} from '@octokit/rest'
import {buildChangelog, fillAdditionalPlaceholders} from './transform' import {buildChangelog, replaceEmptyTemplate} from './transform'
import {failOrError} from './utils' import {failOrError} from './utils'
import {TagInfo} from './tags' import {TagInfo} from './tags'
@@ -61,7 +61,7 @@ export class ReleaseNotes {
if (mergedPullRequests.length === 0) { if (mergedPullRequests.length === 0) {
core.warning(`⚠️ No pull requests found`) core.warning(`⚠️ No pull requests found`)
return fillAdditionalPlaceholders( return replaceEmptyTemplate(
this.options.configuration.empty_template || DefaultConfiguration.empty_template, this.options.configuration.empty_template || DefaultConfiguration.empty_template,
this.options this.options
) )
+66 -50
View File
@@ -4,6 +4,14 @@ import {PullRequestInfo, sortPullRequests} from './pullRequests'
import {ReleaseNotesOptions} from './releaseNotes' import {ReleaseNotesOptions} from './releaseNotes'
import {DiffInfo} from './commits' import {DiffInfo} from './commits'
export interface RegexTransformer {
pattern: RegExp | null
target: string
onProperty?: ('title' | 'author' | 'milestone' | 'body' | 'status' | 'branch')[] | undefined
method?: 'replace' | 'match' | undefined
onEmpty?: string | undefined
}
export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], options: ReleaseNotesOptions): string { export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], options: ReleaseNotesOptions): string {
// sort to target order // sort to target order
const config = options.configuration const config = options.configuration
@@ -51,9 +59,9 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
} }
} }
const placeholderMap = new Map<string, Placeholder>() const placeholders = new Map<string, Placeholder>()
for (const ph of config.custom_placeholders || []) { for (const ph of config.custom_placeholders || []) {
placeholderMap.set(ph.source, ph) placeholders.set(ph.source, ph)
} }
const validatedTransformers = validateTransformers(config.transformers) const validatedTransformers = validateTransformers(config.transformers)
@@ -63,7 +71,7 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
transformedMap.set( transformedMap.set(
pr, pr,
transform( transform(
fillTemplate(pr, config.pr_template || DefaultConfiguration.pr_template, placeholderMap), fillTemplate(pr, config.pr_template || DefaultConfiguration.pr_template, placeholders),
validatedTransformers validatedTransformers
) )
) )
@@ -223,61 +231,63 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
core.info(`✒️ Wrote ${ignoredPrs.length} ignored pull requests down`) core.info(`✒️ Wrote ${ignoredPrs.length} ignored pull requests down`)
// fill template // fill template
let transformedChangelog = config.template || DefaultConfiguration.template const placeholderMap = new Map<string, string>()
transformedChangelog = transformedChangelog.replace(/\${{CHANGELOG}}/g, changelog) placeholderMap.set('CHANGELOG', changelog)
transformedChangelog = transformedChangelog.replace(/\${{UNCATEGORIZED}}/g, changelogUncategorized) placeholderMap.set('UNCATEGORIZED', changelogUncategorized)
transformedChangelog = transformedChangelog.replace(/\${{OPEN}}/g, changelogOpen) placeholderMap.set('OPEN', changelogOpen)
transformedChangelog = transformedChangelog.replace(/\${{IGNORED}}/g, changelogIgnored) placeholderMap.set('IGNORED', changelogIgnored)
// fill other placeholders // fill other placeholders
transformedChangelog = transformedChangelog.replace(/\${{CATEGORIZED_COUNT}}/g, categorizedPrs.length.toString()) placeholderMap.set('CATEGORIZED_COUNT', categorizedPrs.length.toString())
transformedChangelog = transformedChangelog.replace(/\${{UNCATEGORIZED_COUNT}}/g, uncategorizedPrs.length.toString()) placeholderMap.set('UNCATEGORIZED_COUNT', uncategorizedPrs.length.toString())
transformedChangelog = transformedChangelog.replace(/\${{OPEN_COUNT}}/g, openPrs.length.toString()) placeholderMap.set('OPEN_COUNT', openPrs.length.toString())
transformedChangelog = transformedChangelog.replace(/\${{IGNORED_COUNT}}/g, ignoredPrs.length.toString()) placeholderMap.set('IGNORED_COUNT', ignoredPrs.length.toString())
// code change placeholders // code change placeholders
transformedChangelog = transformedChangelog.replace(/\${{CHANGED_FILES}}/g, diffInfo.changedFiles.toString()) placeholderMap.set('CHANGED_FILES', diffInfo.changedFiles.toString())
transformedChangelog = transformedChangelog.replace(/\${{ADDITIONS}}/g, diffInfo.additions.toString()) placeholderMap.set('ADDITIONS', diffInfo.additions.toString())
transformedChangelog = transformedChangelog.replace(/\${{DELETIONS}}/g, diffInfo.deletions.toString()) placeholderMap.set('DELETIONS', diffInfo.deletions.toString())
transformedChangelog = transformedChangelog.replace(/\${{CHANGES}}/g, diffInfo.changes.toString()) placeholderMap.set('CHANGES', diffInfo.changes.toString())
transformedChangelog = transformedChangelog.replace(/\${{COMMITS}}/g, diffInfo.commits.toString()) placeholderMap.set('COMMITS', diffInfo.commits.toString())
transformedChangelog = fillAdditionalPlaceholders(transformedChangelog, options) fillAdditionalPlaceholders(options, placeholderMap)
let transformedChangelog = config.template || DefaultConfiguration.template
transformedChangelog = replacePlaceHolders(transformedChangelog, placeholderMap, placeholders)
core.info(`️ Filled template`) core.info(`️ Filled template`)
return transformedChangelog return transformedChangelog
} }
export function fillAdditionalPlaceholders(text: string, options: ReleaseNotesOptions): string { export function replaceEmptyTemplate(template: string, options: ReleaseNotesOptions): string {
let transformed = text const placeholders = new Map<string, Placeholder>()
for (const ph of options.configuration.custom_placeholders || []) {
placeholders.set(ph.source, ph)
}
const placeholderMap = new Map<string, string>()
fillAdditionalPlaceholders(options, placeholderMap)
return replacePlaceHolders(template, placeholderMap, placeholders)
}
function fillAdditionalPlaceholders(options: ReleaseNotesOptions, placeholderMap: Map<string, string>): void {
// repository placeholders // repository placeholders
transformed = transformed.replace(/\${{OWNER}}/g, options.owner) placeholderMap.set('OWNER', options.owner)
transformed = transformed.replace(/\${{REPO}}/g, options.repo) placeholderMap.set('REPO', options.repo)
transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag.name) placeholderMap.set('FROM_TAG', options.fromTag.name)
transformed = transformed.replace(/\${{FROM_TAG_DATE}}/g, options.fromTag.date?.toISOString() || '') placeholderMap.set('FROM_TAG_DATE', options.fromTag.date?.toISOString() || '')
transformed = transformed.replace(/\${{TO_TAG}}/g, options.toTag.name) placeholderMap.set('TO_TAG', options.toTag.name)
transformed = transformed.replace(/\${{TO_TAG_DATE}}/g, options.toTag.date?.toISOString() || '') placeholderMap.set('TO_TAG_DATE', options.toTag.date?.toISOString() || '')
const fromDate = options.fromTag.date const fromDate = options.fromTag.date
const toDate = options.toTag.date const toDate = options.toTag.date
if (fromDate !== undefined && toDate !== undefined) { if (fromDate !== undefined && toDate !== undefined) {
transformed = transformed.replace(/\${{DAYS_SINCE}}/g, toDate.diff(fromDate, 'days').toString() || '') placeholderMap.set('DAYS_SINCE', toDate.diff(fromDate, 'days').toString() || '')
} else { } else {
transformed = transformed.replace(/\${{DAYS_SINCE}}/g, '') placeholderMap.set('DAYS_SINCE', '')
} }
transformed = transformed.replace( placeholderMap.set(
/\${{RELEASE_DIFF}}/g, 'RELEASE_DIFF',
`https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag.name}...${options.toTag.name}` `https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag.name}...${options.toTag.name}`
) )
return transformed
} }
function haveCommonElements(arr1: string[], arr2: Set<string>): Boolean { function fillTemplate(pr: PullRequestInfo, template: string, placeholders: Map<string, Placeholder>): string {
return arr1.some(item => arr2.has(item))
}
function haveEveryElements(arr1: string[], arr2: Set<string>): Boolean {
return arr1.every(item => arr2.has(item))
}
function fillTemplate(pr: PullRequestInfo, template: string, customPlaceholders: Map<string, Placeholder>): string {
const placeholderMap = new Map<string, string>() const placeholderMap = new Map<string, string>()
placeholderMap.set('NUMBER', pr.number.toString()) placeholderMap.set('NUMBER', pr.number.toString())
placeholderMap.set('TITLE', pr.title) placeholderMap.set('TITLE', pr.title)
@@ -295,19 +305,25 @@ function fillTemplate(pr: PullRequestInfo, template: string, customPlaceholders:
placeholderMap.set('APPROVERS', pr.approvedReviewers?.join(', ') || '') placeholderMap.set('APPROVERS', pr.approvedReviewers?.join(', ') || '')
placeholderMap.set('BRANCH', pr.branch || '') placeholderMap.set('BRANCH', pr.branch || '')
placeholderMap.set('BASE_BRANCH', pr.baseBranch) placeholderMap.set('BASE_BRANCH', pr.baseBranch)
return replacePlaceHolders(template, placeholderMap, placeholders)
}
function replacePlaceHolders(
template: string,
placeholderMap: Map<string, string>,
placeholders: Map<string, Placeholder>
): string {
let transformed = template let transformed = template
for (const [key, value] of placeholderMap) { for (const [key, value] of placeholderMap) {
transformed = transformed.replaceAll(`\${{${key}}}`, value) transformed = transformed.replaceAll(`\${{${key}}}`, value)
// replace custom placeholders // replace custom placeholders
transformed = applyCustomPlaceholder(transformed, value, customPlaceholders.get(key)) transformed = applyCustomPlaceholder(transformed, value, placeholders.get(key))
} }
return transformed return transformed
} }
function applyCustomPlaceholder(template: string, value: string, placeholder: Placeholder | undefined) { function applyCustomPlaceholder(template: string, value: string, placeholder: Placeholder | undefined): string {
if (placeholder) { if (placeholder) {
const transformer = validateTransformer(placeholder.transformer) const transformer = validateTransformer(placeholder.transformer)
if (transformer?.pattern) { if (transformer?.pattern) {
@@ -427,10 +443,10 @@ function extractValuesFromString(value: string, extractor: RegexTransformer): st
return null return null
} }
export interface RegexTransformer { function haveCommonElements(arr1: string[], arr2: Set<string>): Boolean {
pattern: RegExp | null return arr1.some(item => arr2.has(item))
target: string }
onProperty?: ('title' | 'author' | 'milestone' | 'body' | 'status' | 'branch')[] | undefined
method?: 'replace' | 'match' | undefined function haveEveryElements(arr1: string[], arr2: Set<string>): Boolean {
onEmpty?: string | undefined return arr1.every(item => arr2.has(item))
} }