- introduce new configuration option to define category labels to be exhaustive

- require all labels of a category to be present in the matching PR
- update to typescript 4.4.x
- recompile dist
This commit is contained in:
Mike Penz
2021-08-27 11:41:20 +02:00
parent 354828ea24
commit cfac2f37a1
11 changed files with 203 additions and 125 deletions
+2 -1
View File
@@ -290,6 +290,7 @@ 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 |
| category.exhaustive | Will require all labels defined within this category to be present on the matching PR. |
| 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 | The sort order of pull requests. [ASC, DESC] | | 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 | | template | Specifies the global template to pick for creating the changelog. See [Template placeholders](#template-placeholders) for possible values |
@@ -325,7 +326,7 @@ $ npm run build && npm run package
$ npm test $ npm test
# Verify lint is happy # Verify lint is happy
$ npm run lint -- --fix $ npm run lint -- --fixnpm run lint -- --fix
``` ```
It's suggested to export the token to your path before running the tests so that API calls can be done to GitHub. It's suggested to export the token to your path before running the tests so that API calls can be done to GitHub.
+121 -72
View File
@@ -6,79 +6,79 @@ import { DefaultConfiguration } from '../src/configuration';
jest.setTimeout(180000) jest.setTimeout(180000)
let configuration = DefaultConfiguration let configuration = DefaultConfiguration
configuration.categories = [ configuration.categories = [
{ {
"title": "## 🚀 Features", "title": "## 🚀 Features",
"labels": ["[Feature]"] "labels": ["[Feature]"]
}, },
{ {
"title": "## 🐛 Fixes", "title": "## 🐛 Fixes",
"labels": ["[Bug]", "[Issue]"] "labels": ["[Bug]", "[Issue]"]
}, },
{ {
"title": "## 🧪 Tests", "title": "## 🧪 Tests",
"labels": ["[Test]"] "labels": ["[Test]"]
} }
] ]
let mergedPullRequests: PullRequestInfo[] = [] let mergedPullRequests: PullRequestInfo[] = []
mergedPullRequests.push({ mergedPullRequests.push({
number: 1, number: 1,
title: "[Feature][AB-1234] - this is a PR 1 title message", title: "[Feature][AB-1234] - this is a PR 1 title message",
htmlURL: "", htmlURL: "",
baseBranch: "", baseBranch: "",
mergedAt: moment(), mergedAt: moment(),
mergeCommitSha: "sha1", mergeCommitSha: "sha1",
author: "Mike", author: "Mike",
repoName: "test-repo", repoName: "test-repo",
labels: new Set<string>(), labels: new Set<string>(),
milestone: "", milestone: "",
body: "no magic body for this matter", body: "no magic body for this matter",
assignees: [], assignees: [],
requestedReviewers: [] requestedReviewers: []
}, { }, {
number: 2, number: 2,
title: "[Issue][AB-4321] - this is a PR 2 title message", title: "[Issue][AB-4321] - this is a PR 2 title message",
htmlURL: "", htmlURL: "",
baseBranch: "", baseBranch: "",
mergedAt: moment(), mergedAt: moment(),
mergeCommitSha: "sha1", mergeCommitSha: "sha1",
author: "Mike", author: "Mike",
repoName: "test-repo", repoName: "test-repo",
labels: new Set<string>(), labels: new Set<string>(),
milestone: "", milestone: "",
body: "no magic body for this matter", body: "no magic body for this matter",
assignees: [], assignees: [],
requestedReviewers: [] requestedReviewers: []
}, { }, {
number: 3, number: 3,
title: "[Issue][Feature][AB-1234321] - this is a PR 3 title message", title: "[Issue][Feature][AB-1234321] - this is a PR 3 title message",
htmlURL: "", htmlURL: "",
baseBranch: "", baseBranch: "",
mergedAt: moment(), mergedAt: moment(),
mergeCommitSha: "sha1", mergeCommitSha: "sha1",
author: "Mike", author: "Mike",
repoName: "test-repo", repoName: "test-repo",
labels: new Set<string>(), labels: new Set<string>(),
milestone: "", milestone: "",
body: "no magic body for this matter", body: "no magic body for this matter",
assignees: [], assignees: [],
requestedReviewers: [] requestedReviewers: []
}, { }, {
number: 4, number: 4,
title: "[AB-404] - not found label", title: "[AB-404] - not found label",
htmlURL: "", htmlURL: "",
baseBranch: "", baseBranch: "",
mergedAt: moment(), mergedAt: moment(),
mergeCommitSha: "sha1", mergeCommitSha: "sha1",
author: "Mike", author: "Mike",
repoName: "test-repo", repoName: "test-repo",
labels: new Set<string>(), labels: new Set<string>(),
milestone: "", milestone: "",
body: "no magic body for this matter", body: "no magic body for this matter",
assignees: [], assignees: [],
requestedReviewers: [] requestedReviewers: []
}) })
it('Extract label from title, combined regex', async () => { it('Extract label from title, combined regex', async () => {
configuration.label_extractor = [ configuration.label_extractor = [
@@ -189,3 +189,52 @@ it('Extract label from title, match multiple', async () => {
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`) 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`)
}) })
it('Extract label from title, match multiple exhaustive', async () => {
let customConfig = configuration
customConfig.categories = [
{
"title": "## 🚀 Features and 🐛 Issues",
"labels": ["[Feature]", "[Issue]"],
"exhaustive": true
},
{
"title": "## 🚀 Features",
"labels": ["[Feature]", "[Feature2]"],
"exhaustive": true
},
{
"title": "## 🐛 Fixes",
"labels": ["[Issue]", "[Issue2]"],
"exhaustive": true
}
]
customConfig.label_extractor = [
{
"pattern": "\\[Feature\\]",
"on_property": "title",
"method": "match"
},
{
"pattern": "\\[Issue\\]",
"on_property": "title",
"method": "match"
}
]
const resultChangelog = buildChangelog(
mergedPullRequests,
{
owner: "mikepenz",
repo: "test-repo",
fromTag: "1.0.0",
toTag: "2.0.0",
failOnError: false,
commitMode: false,
configuration: customConfig
}
)
expect(resultChangelog).toStrictEqual(`## 🚀 Features and 🐛 Issues\n\n- [Issue][Feature][AB-1234321] - this is a PR 3 title message\n - PR: #3\n\n`)
})
Generated Vendored
+37 -26
View File
@@ -80,7 +80,7 @@ class Commits {
sha: commit.sha || '', sha: commit.sha || '',
summary: commit.commit.message.split('\n')[0], summary: commit.commit.message.split('\n')[0],
message: commit.commit.message, message: commit.commit.message,
date: moment_1.default((_a = commit.commit.committer) === null || _a === void 0 ? void 0 : _a.date), date: (0, moment_1.default)((_a = commit.commit.committer) === null || _a === void 0 ? void 0 : _a.date),
author: ((_b = commit.commit.author) === null || _b === void 0 ? void 0 : _b.name) || '', author: ((_b = commit.commit.author) === null || _b === void 0 ? void 0 : _b.name) || '',
prNumber: undefined prNumber: undefined
}); });
@@ -269,7 +269,7 @@ class GitCommandManager {
} }
execGit(args, allowAllExitCodes = false, silent = false) { execGit(args, allowAllExitCodes = false, silent = false) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
utils_1.directoryExistsSync(this.workingDirectory, true); (0, utils_1.directoryExistsSync)(this.workingDirectory, true);
const result = new GitOutput(); const result = new GitOutput();
const stdout = []; const stdout = [];
const options = { const options = {
@@ -349,10 +349,10 @@ function run() {
try { try {
// read in path specification, resolve github workspace, and repo path // read in path specification, resolve github workspace, and repo path
const inputPath = core.getInput('path'); const inputPath = core.getInput('path');
const repositoryPath = utils_1.retrieveRepositoryPath(inputPath); const repositoryPath = (0, utils_1.retrieveRepositoryPath)(inputPath);
// read in configuration file if possible // read in configuration file if possible
const configurationFile = core.getInput('configuration'); const configurationFile = core.getInput('configuration');
const configuration = utils_1.resolveConfiguration(repositoryPath, configurationFile); const configuration = (0, utils_1.resolveConfiguration)(repositoryPath, configurationFile);
// read in repository inputs // read in repository inputs
const token = core.getInput('token'); const token = core.getInput('token');
const owner = core.getInput('owner') || github.context.repo.owner; const owner = core.getInput('owner') || github.context.repo.owner;
@@ -370,10 +370,10 @@ function run() {
const outputFile = core.getInput('outputFile'); const outputFile = core.getInput('outputFile');
if (outputFile !== '') { if (outputFile !== '') {
core.debug(`Enabled writing the changelog to disk`); core.debug(`Enabled writing the changelog to disk`);
utils_1.writeOutput(repositoryPath, outputFile, result); (0, utils_1.writeOutput)(repositoryPath, outputFile, result);
} }
} }
catch (error) { catch (error /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
core.setFailed(error.message); core.setFailed(error.message);
} }
}); });
@@ -444,7 +444,7 @@ class PullRequests {
}); });
return mapPullRequest(data); return mapPullRequest(data);
} }
catch (e) { catch (e /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
core.warning(`⚠️ Cannot find PR ${owner}/${repo}#${prNumber} - ${e.message}`); core.warning(`⚠️ Cannot find PR ${owner}/${repo}#${prNumber} - ${e.message}`);
return null; return null;
} }
@@ -471,7 +471,7 @@ class PullRequests {
} }
const firstPR = prs[0]; const firstPR = prs[0];
if (firstPR === undefined || if (firstPR === undefined ||
(firstPR.merged_at && fromDate.isAfter(moment_1.default(firstPR.merged_at))) || (firstPR.merged_at && fromDate.isAfter((0, moment_1.default)(firstPR.merged_at))) ||
mergedPRs.length >= maxPullRequests) { mergedPRs.length >= maxPullRequests) {
if (mergedPRs.length >= maxPullRequests) { if (mergedPRs.length >= maxPullRequests) {
core.warning(`⚠️ Reached 'maxPullRequests' count ${maxPullRequests}`); core.warning(`⚠️ Reached 'maxPullRequests' count ${maxPullRequests}`);
@@ -526,7 +526,7 @@ const mapPullRequest = (pr) => {
title: pr.title, title: pr.title,
htmlURL: pr.html_url, htmlURL: pr.html_url,
baseBranch: pr.base.ref, baseBranch: pr.base.ref,
mergedAt: moment_1.default(pr.merged_at), mergedAt: (0, moment_1.default)(pr.merged_at),
mergeCommitSha: pr.merge_commit_sha || '', mergeCommitSha: pr.merge_commit_sha || '',
author: ((_a = pr.user) === null || _a === void 0 ? void 0 : _a.login) || '', author: ((_a = pr.user) === null || _a === void 0 ? void 0 : _a.login) || '',
repoName: pr.base.repo.full_name, repoName: pr.base.repo.full_name,
@@ -612,7 +612,7 @@ class ReleaseNotes {
return null; return null;
} }
core.startGroup('📦 Build changelog'); core.startGroup('📦 Build changelog');
const resultChangelog = transform_1.buildChangelog(mergedPullRequests, this.options); const resultChangelog = (0, transform_1.buildChangelog)(mergedPullRequests, this.options);
core.endGroup(); core.endGroup();
return resultChangelog; return resultChangelog;
}); });
@@ -627,7 +627,7 @@ class ReleaseNotes {
commits = yield commitsApi.getDiff(owner, repo, fromTag, toTag); commits = yield commitsApi.getDiff(owner, repo, fromTag, toTag);
} }
catch (error) { catch (error) {
utils_1.failOrError(`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, failOnError); (0, utils_1.failOrError)(`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, failOnError);
return []; return [];
} }
if (commits.length === 0) { if (commits.length === 0) {
@@ -659,7 +659,7 @@ class ReleaseNotes {
const pullRequestsApi = new pullRequests_1.PullRequests(octokit); const pullRequestsApi = new pullRequests_1.PullRequests(octokit);
const pullRequests = yield pullRequestsApi.getBetweenDates(owner, repo, fromDate, toDate, configuration.max_pull_requests || configuration_1.DefaultConfiguration.max_pull_requests); const pullRequests = yield pullRequestsApi.getBetweenDates(owner, repo, fromDate, toDate, configuration.max_pull_requests || configuration_1.DefaultConfiguration.max_pull_requests);
core.info(`️ Retrieved ${pullRequests.length} merged PRs for ${owner}/${repo}`); core.info(`️ Retrieved ${pullRequests.length} merged PRs for ${owner}/${repo}`);
const prCommits = commits_1.filterCommits(commits, configuration.exclude_merge_branches || const prCommits = (0, commits_1.filterCommits)(commits, configuration.exclude_merge_branches ||
configuration_1.DefaultConfiguration.exclude_merge_branches); configuration_1.DefaultConfiguration.exclude_merge_branches);
core.info(`️ Retrieved ${prCommits.length} release commits for ${owner}/${repo}`); core.info(`️ Retrieved ${prCommits.length} release commits for ${owner}/${repo}`);
// create array of commits for this release // create array of commits for this release
@@ -691,7 +691,7 @@ class ReleaseNotes {
if (commits.length === 0) { if (commits.length === 0) {
return []; return [];
} }
const prCommits = commits_1.filterCommits(commits, configuration.exclude_merge_branches || const prCommits = (0, commits_1.filterCommits)(commits, configuration.exclude_merge_branches ||
configuration_1.DefaultConfiguration.exclude_merge_branches); configuration_1.DefaultConfiguration.exclude_merge_branches);
core.info(`️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`); core.info(`️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`);
return prCommits.map(function (commit) { return prCommits.map(function (commit) {
@@ -778,7 +778,7 @@ class ReleaseNotesBuilder {
var _a, _b; var _a, _b;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
if (!this.owner) { if (!this.owner) {
utils_1.failOrError(`💥 Missing or couldn't resolve 'owner'`, this.failOnError); (0, utils_1.failOrError)(`💥 Missing or couldn't resolve 'owner'`, this.failOnError);
return null; return null;
} }
else { else {
@@ -786,7 +786,7 @@ class ReleaseNotesBuilder {
core.debug(`Resolved 'owner' as ${this.owner}`); core.debug(`Resolved 'owner' as ${this.owner}`);
} }
if (!this.repo) { if (!this.repo) {
utils_1.failOrError(`💥 Missing or couldn't resolve 'owner'`, this.failOnError); (0, utils_1.failOrError)(`💥 Missing or couldn't resolve 'owner'`, this.failOnError);
return null; return null;
} }
else { else {
@@ -805,7 +805,7 @@ class ReleaseNotesBuilder {
configuration_1.DefaultConfiguration.max_tags_to_fetch, this.configuration.tag_resolver || configuration_1.DefaultConfiguration.tag_resolver); configuration_1.DefaultConfiguration.max_tags_to_fetch, this.configuration.tag_resolver || configuration_1.DefaultConfiguration.tag_resolver);
const thisTag = (_a = tagRange.to) === null || _a === void 0 ? void 0 : _a.name; const thisTag = (_a = tagRange.to) === null || _a === void 0 ? void 0 : _a.name;
if (!thisTag) { if (!thisTag) {
utils_1.failOrError(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError); (0, utils_1.failOrError)(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError);
return null; return null;
} }
else { else {
@@ -815,7 +815,7 @@ class ReleaseNotesBuilder {
} }
const previousTag = (_b = tagRange.from) === null || _b === void 0 ? void 0 : _b.name; const previousTag = (_b = tagRange.from) === null || _b === void 0 ? void 0 : _b.name;
if (previousTag == null) { if (previousTag == null) {
utils_1.failOrError(`💥 Unable to retrieve previous tag given ${this.toTag}`, this.failOnError); (0, utils_1.failOrError)(`💥 Unable to retrieve previous tag given ${this.toTag}`, this.failOnError);
return null; return null;
} }
this.fromTag = previousTag; this.fromTag = previousTag;
@@ -832,7 +832,7 @@ class ReleaseNotesBuilder {
}; };
const releaseNotes = new releaseNotes_1.ReleaseNotes(octokit, options); const releaseNotes = new releaseNotes_1.ReleaseNotes(octokit, options);
return ((yield releaseNotes.pull()) || return ((yield releaseNotes.pull()) ||
transform_1.fillAdditionalPlaceholders(this.configuration.empty_template || (0, transform_1.fillAdditionalPlaceholders)(this.configuration.empty_template ||
configuration_1.DefaultConfiguration.empty_template, options)); configuration_1.DefaultConfiguration.empty_template, options));
}); });
} }
@@ -953,7 +953,7 @@ class Tags {
else { else {
core.info(`️ Only one tag found for the given repository. Usually this is the case for the initial release.`); core.info(`️ Only one tag found for the given repository. Usually this is the case for the initial release.`);
// if not specified try to retrieve tag from git // if not specified try to retrieve tag from git
const gitHelper = yield gitHelper_1.createCommandManager(repositoryPath); const gitHelper = yield (0, gitHelper_1.createCommandManager)(repositoryPath);
const initialCommit = yield gitHelper.initialCommit(); const initialCommit = yield gitHelper.initialCommit();
core.info(`🔖 Resolved initial commit (${initialCommit}) from 'git rev-list --max-parents=0 HEAD'`); core.info(`🔖 Resolved initial commit (${initialCommit}) from 'git rev-list --max-parents=0 HEAD'`);
return { name: initialCommit, commit: initialCommit }; return { name: initialCommit, commit: initialCommit };
@@ -991,7 +991,7 @@ class Tags {
} }
else { else {
// if not specified try to retrieve tag from git // if not specified try to retrieve tag from git
const gitHelper = yield gitHelper_1.createCommandManager(repositoryPath); const gitHelper = yield (0, gitHelper_1.createCommandManager)(repositoryPath);
const latestTag = yield gitHelper.latestTag(); const latestTag = yield gitHelper.latestTag();
core.info(`🔖 Resolved current tag (${latestTag}) from 'git rev-list --tags --skip=0 --max-count=1'`); core.info(`🔖 Resolved current tag (${latestTag}) from 'git rev-list --tags --skip=0 --max-count=1'`);
resultToTag = { resultToTag = {
@@ -1133,7 +1133,7 @@ function buildChangelog(prs, options) {
const config = options.configuration; const config = options.configuration;
const sort = config.sort || configuration_1.DefaultConfiguration.sort; const sort = config.sort || configuration_1.DefaultConfiguration.sort;
const sortAsc = sort.toUpperCase() === 'ASC'; const sortAsc = sort.toUpperCase() === 'ASC';
prs = pullRequests_1.sortPullRequests(prs, sortAsc); prs = (0, pullRequests_1.sortPullRequests)(prs, sortAsc);
core.info(`️ Sorted all pull requests ascending: ${sort}`); core.info(`️ Sorted all pull requests ascending: ${sort}`);
// extract additional labels from the commit message // extract additional labels from the commit message
const labelExtractors = validateTransformers(config.label_extractor); const labelExtractors = validateTransformers(config.label_extractor);
@@ -1195,9 +1195,17 @@ function buildChangelog(prs, options) {
} }
let matched = false; let matched = false;
for (const [category, pullRequests] of categorized) { for (const [category, pullRequests] of categorized) {
if (haveCommonElements(category.labels.map(lbl => lbl.toLocaleLowerCase()), pr.labels)) { if (category.exhaustive === true) {
pullRequests.push(body); if (haveEveryElements(category.labels.map(lbl => lbl.toLocaleLowerCase()), pr.labels)) {
matched = true; pullRequests.push(body);
matched = true;
}
}
else {
if (haveCommonElements(category.labels.map(lbl => lbl.toLocaleLowerCase()), pr.labels)) {
pullRequests.push(body);
matched = true;
}
} }
} }
if (!matched) { if (!matched) {
@@ -1264,6 +1272,9 @@ exports.fillAdditionalPlaceholders = fillAdditionalPlaceholders;
function haveCommonElements(arr1, arr2) { function haveCommonElements(arr1, arr2) {
return arr1.some(item => arr2.has(item)); return arr1.some(item => arr2.has(item));
} }
function haveEveryElements(arr1, arr2) {
return arr1.every(item => arr2.has(item));
}
function fillTemplate(pr, template) { function fillTemplate(pr, template) {
var _a, _b, _c; var _a, _b, _c;
let transformed = template; let transformed = template;
@@ -1432,7 +1443,7 @@ function directoryExistsSync(inputPath, required) {
try { try {
stats = fs.statSync(inputPath); stats = fs.statSync(inputPath);
} }
catch (error) { catch (error /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
if (error.code === 'ENOENT') { if (error.code === 'ENOENT') {
if (!required) { if (!required) {
return false; return false;
@@ -1460,7 +1471,7 @@ function writeOutput(githubWorkspacePath, outputFile, changelog) {
try { try {
fs.writeFileSync(outputPath, changelog); fs.writeFileSync(outputPath, changelog);
} }
catch (error) { catch (error /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
core.warning(`⚠️ Could not write the file to disk - ${error.message}`); core.warning(`⚠️ Could not write the file to disk - ${error.message}`);
} }
} }
Generated Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
+7 -7
View File
@@ -31,7 +31,7 @@
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"prettier": "2.3.2", "prettier": "2.3.2",
"ts-jest": "^27.0.5", "ts-jest": "^27.0.5",
"typescript": "^4.3.5" "typescript": "^4.4.2"
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
@@ -6616,9 +6616,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.3.5", "version": "4.4.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz",
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==",
"dev": true, "dev": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
@@ -12049,9 +12049,9 @@
} }
}, },
"typescript": { "typescript": {
"version": "4.3.5", "version": "4.4.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz",
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==",
"dev": true "dev": true
}, },
"unbox-primitive": { "unbox-primitive": {
+1 -1
View File
@@ -54,6 +54,6 @@
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"prettier": "2.3.2", "prettier": "2.3.2",
"ts-jest": "^27.0.5", "ts-jest": "^27.0.5",
"typescript": "^4.3.5" "typescript": "^4.4.2"
} }
} }
+6 -5
View File
@@ -16,19 +16,20 @@ export interface Configuration {
} }
export interface Category { export interface Category {
title: string title: string // the title of this category
labels: string[] labels: string[] // labels to associate PRs to this category
exhaustive?: boolean // requires all labels to be present in the PR
} }
export interface Transformer { export interface Transformer {
pattern: string pattern: string // the regex pattern to match
target?: string target?: string // the target string to transform the source string using the regex to
flags?: string // the regex flag to use for RegExp flags?: string // the regex flag to use for RegExp
} }
export interface Extractor extends Transformer { export interface Extractor extends Transformer {
on_property?: 'title' | 'author' | 'milestone' | 'body' | undefined // retrieve the property to extract the value from on_property?: 'title' | 'author' | 'milestone' | 'body' | undefined // retrieve the property to extract the value from
method?: 'replace' | 'match' | undefined // the method to use to extract the value method?: 'replace' | 'match' | undefined // the method to use to extract the value, `match` will not use the `target` property
} }
export interface TagResolver { export interface TagResolver {
+1 -1
View File
@@ -56,7 +56,7 @@ async function run(): Promise<void> {
core.debug(`Enabled writing the changelog to disk`) core.debug(`Enabled writing the changelog to disk`)
writeOutput(repositoryPath, outputFile, result) writeOutput(repositoryPath, outputFile, result)
} }
} catch (error) { } catch (error: any /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
core.setFailed(error.message) core.setFailed(error.message)
} }
} }
+1 -1
View File
@@ -40,7 +40,7 @@ export class PullRequests {
}) })
return mapPullRequest(data) return mapPullRequest(data)
} catch (e) { } catch (e: any /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
core.warning( core.warning(
`⚠️ Cannot find PR ${owner}/${repo}#${prNumber} - ${e.message}` `⚠️ Cannot find PR ${owner}/${repo}#${prNumber} - ${e.message}`
) )
+24 -8
View File
@@ -103,14 +103,26 @@ export function buildChangelog(
let matched = false let matched = false
for (const [category, pullRequests] of categorized) { for (const [category, pullRequests] of categorized) {
if ( if (category.exhaustive === true) {
haveCommonElements( if (
category.labels.map(lbl => lbl.toLocaleLowerCase()), haveEveryElements(
pr.labels category.labels.map(lbl => lbl.toLocaleLowerCase()),
) pr.labels
) { )
pullRequests.push(body) ) {
matched = true pullRequests.push(body)
matched = true
}
} else {
if (
haveCommonElements(
category.labels.map(lbl => lbl.toLocaleLowerCase()),
pr.labels
)
) {
pullRequests.push(body)
matched = true
}
} }
} }
@@ -213,6 +225,10 @@ function haveCommonElements(arr1: string[], arr2: Set<string>): Boolean {
return arr1.some(item => arr2.has(item)) 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): string { function fillTemplate(pr: PullRequestInfo, template: string): string {
let transformed = template let transformed = template
transformed = transformed.replace(/\${{NUMBER}}/g, pr.number.toString()) transformed = transformed.replace(/\${{NUMBER}}/g, pr.number.toString())
+2 -2
View File
@@ -96,7 +96,7 @@ export function directoryExistsSync(
let stats: fs.Stats let stats: fs.Stats
try { try {
stats = fs.statSync(inputPath) stats = fs.statSync(inputPath)
} catch (error) { } catch (error: any /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
if (error.code === 'ENOENT') { if (error.code === 'ENOENT') {
if (!required) { if (!required) {
return false return false
@@ -132,7 +132,7 @@ export function writeOutput(
core.debug(`outputPath = '${outputPath}'`) core.debug(`outputPath = '${outputPath}'`)
try { try {
fs.writeFileSync(outputPath, changelog) fs.writeFileSync(outputPath, changelog)
} catch (error) { } catch (error: any /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
core.warning(`⚠️ Could not write the file to disk - ${error.message}`) core.warning(`⚠️ Could not write the file to disk - ${error.message}`)
} }
} }