- introduce new additional placeholders useable for building the changelog

| **Placeholder**            | **Description**                                                                                    | **Empty** |
|----------------------------|----------------------------------------------------------------------------------------------------|:---------:|
| `${{CHANGED_FILES}}`       | The count of changed files.                                                                        |           |
| `${{ADDITIONS}}`           | The count of code additions (lines).                                                               |           |
| `${{DELETIONS}}`           | The count of code deletions (lines).                                                               |           |
| `${{CHANGES}}`             | The count of total changes (lines).                                                                |           |
| `${{COMMITS}}`             | The count of commits in this release.                                                              |           |

- restructure project to return additional diff related information along the individual commits
- update testcases to verify functionality of new placeholders
This commit is contained in:
Mike Penz
2022-07-26 14:14:16 +02:00
parent 2b8bedc47a
commit 55354469a8
11 changed files with 245 additions and 108 deletions
+11 -1
View File
@@ -86,6 +86,11 @@ A full set list of possible output values for this action.
| `outputs.categorized_prs` | Count of PRs which were successfully categorized as part of the action. | | `outputs.categorized_prs` | Count of PRs which were successfully categorized as part of the action. |
| `outputs.open_prs` | Count of open PRs. Only fetched if `includeOpen` is enabled. | | `outputs.open_prs` | Count of open PRs. Only fetched if `includeOpen` is enabled. |
| `outputs.uncategorized_prs` | Count of PRs which were not categorized as part of the action. | | `outputs.uncategorized_prs` | Count of PRs which were not categorized as part of the action. |
| `outputs.changed_files` | Count of changed files in this release. |
| `outputs.additions` | Count of code additions in this release (lines). |
| `outputs.deletions` | Count of code deletions in this release (lines). |
| `outputs.changes` | Total count of changes in this release (lines). |
| `outputs.commits` | Count of commits which have been added in this release. |
## Full Sample 🖥️ ## Full Sample 🖥️
@@ -309,6 +314,11 @@ Table of supported placeholders allowed to be used in the `template` and `empty_
| `${{FROM_TAG}}` | Defines the 'start' from where the changelog did consider merged pull requests | x | | `${{FROM_TAG}}` | Defines the 'start' from where the changelog did consider merged pull requests | x |
| `${{TO_TAG}}` | Defines until which tag the changelog did consider merged pull requests | x | | `${{TO_TAG}}` | Defines until which tag the changelog did consider merged pull requests | x |
| `${{RELEASE_DIFF}}` | Introduces a link to the full diff between from tag and to tag releases | x | | `${{RELEASE_DIFF}}` | Introduces a link to the full diff between from tag and to tag releases | x |
| `${{CHANGED_FILES}}` | The count of changed files. | |
| `${{ADDITIONS}}` | The count of code additions (lines). | |
| `${{DELETIONS}}` | The count of code deletions (lines). | |
| `${{CHANGES}}` | The count of total changes (lines). | |
| `${{COMMITS}}` | The count of commits in this release. | |
| `${{CATEGORIZED_COUNT}}` | The count of PRs which were categorized | | | `${{CATEGORIZED_COUNT}}` | The count of PRs which were categorized | |
| `${{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. | |
@@ -404,7 +414,7 @@ export GITHUB_TOKEN=your_personal_github_pat
All patches and changes applied to the original source are licensed under the Apache 2.0 license. All patches and changes applied to the original source are licensed under the Apache 2.0 license.
Copyright 2021 Mike Penz Copyright 2022 Mike Penz
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
+1 -1
View File
@@ -25,7 +25,7 @@ it('Should have empty changelog (tags)', async () => {
const changeLog = await releaseNotes.pull() const changeLog = await releaseNotes.pull()
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual(null) expect(changeLog).toStrictEqual("- no changes")
}) })
it('Should match generated changelog (tags)', async () => { it('Should match generated changelog (tags)', async () => {
+3 -3
View File
@@ -103,7 +103,7 @@ it('Should fill empty placeholders', async () => {
const changeLog = await releaseNotesBuilder.build() const changeLog = await releaseNotesBuilder.build()
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual( expect(changeLog).toStrictEqual(
`mikepenz\nrelease-changelog-builder-action\nv0.0.2\nv0.0.3` `mikepenz\nrelease-changelog-builder-action\nv0.0.2\nv0.0.3\nhttps://github.com/mikepenz/release-changelog-builder-action/compare/v0.0.2...v0.0.3`
) )
}) })
@@ -131,7 +131,7 @@ it('Should fill `template` placeholders', async () => {
const changeLog = await releaseNotesBuilder.build() const changeLog = await releaseNotesBuilder.build()
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual( expect(changeLog).toStrictEqual(
`## 🧪 Tests\n\n- [CI] Specify Test Case\n - PR: #10\n\n\n\n\nmikepenz\nrelease-changelog-builder-action\nv0.0.1\nv0.0.3\n1\n0\n0` `## 🧪 Tests\n\n- [CI] Specify Test Case\n - PR: #10\n\n\n\n\nmikepenz\nrelease-changelog-builder-action\nv0.0.1\nv0.0.3\nhttps://github.com/mikepenz/release-changelog-builder-action/compare/v0.0.1...v0.0.3\n1\n0\n0\n19\n14827\n444\n15271\n3`
) )
}) })
@@ -159,7 +159,7 @@ it('Should fill `template` placeholders, ignore', async () => {
const changeLog = await releaseNotesBuilder.build() const changeLog = await releaseNotesBuilder.build()
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual( expect(changeLog).toStrictEqual(
`## 🚀 Features\n\n- Enhance sorting by using proper semver\n - PR: #51\n\n## 🧪 Tests\n\n- Improve test cases\n - PR: #49\n\n\n- Bump @types/node from 14.11.8 to 14.11.10\n - PR: #47\n- Adjust code to move fromTag resolving to main.ts\n - PR: #48\n- dev -> main\n - PR: #52\n- Update package.json to updated description\n - PR: #53\n- dev -> main\n - PR: #54\n\n- New additional placeholders for \`template\` and \`empty_template\`\n - PR: #50\n\nmikepenz\nrelease-changelog-builder-action\nv0.9.1\nv0.9.5\n2\n5\n1` `## 🚀 Features\n\n- Enhance sorting by using proper semver\n - PR: #51\n\n## 🧪 Tests\n\n- Improve test cases\n - PR: #49\n\n\n- Bump @types/node from 14.11.8 to 14.11.10\n - PR: #47\n- Adjust code to move fromTag resolving to main.ts\n - PR: #48\n- dev -> main\n - PR: #52\n- Update package.json to updated description\n - PR: #53\n- dev -> main\n - PR: #54\n\n- New additional placeholders for \`template\` and \`empty_template\`\n - PR: #50\n\nmikepenz\nrelease-changelog-builder-action\nv0.9.1\nv0.9.5\nhttps://github.com/mikepenz/release-changelog-builder-action/compare/v0.9.1...v0.9.5\n2\n5\n1\n16\n2931\n450\n3381\n26`
) )
}) })
+14 -13
View File
@@ -2,6 +2,7 @@ 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, Configuration } from '../src/configuration';
import { DefaultDiffInfo } from '../src/commits';
jest.setTimeout(180000) jest.setTimeout(180000)
@@ -130,7 +131,7 @@ it('Extract label from title, combined regex', async () => {
} }
] ]
const resultChangelog = buildChangelog(mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: '1.0.0',
@@ -159,7 +160,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(prs, { const resultChangelog = buildChangelog(DefaultDiffInfo, prs, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: '1.0.0',
@@ -190,7 +191,7 @@ it('Extract label from title, split regex', async () => {
} }
] ]
const resultChangelog = buildChangelog(mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: '1.0.0',
@@ -221,7 +222,7 @@ it('Extract label from title, match', async () => {
} }
] ]
const resultChangelog = buildChangelog(mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: '1.0.0',
@@ -247,7 +248,7 @@ it('Extract label from title, match multiple', async () => {
} }
] ]
const resultChangelog = buildChangelog(mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: '1.0.0',
@@ -274,7 +275,7 @@ it('Extract label from title, match multiple, custon non matching label', async
} }
] ]
const resultChangelog = buildChangelog(mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: '1.0.0',
@@ -388,7 +389,7 @@ it('Match multiple labels exhaustive for category', async () => {
} }
] ]
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: '1.0.0',
@@ -413,7 +414,7 @@ it('Deduplicate duplicated PRs', async () => {
method: 'match' method: 'match'
} }
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: '1.0.0',
@@ -439,7 +440,7 @@ it('Deduplicate duplicated PRs DESC', async () => {
method: 'match' method: 'match'
} }
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: '1.0.0',
@@ -471,7 +472,7 @@ it('Use empty_content for empty category', async () => {
} }
] ]
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: '1.0.0',
@@ -493,7 +494,7 @@ it('Commit SHA-1 in commitMode', async () => {
customConfig.sort = "DESC" customConfig.sort = "DESC"
customConfig.pr_template = "${{MERGE_SHA}}" customConfig.pr_template = "${{MERGE_SHA}}"
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: '1.0.0',
@@ -514,7 +515,7 @@ it('Release Diff', async () => {
const customConfig = Object.assign({}, DefaultConfiguration) const customConfig = Object.assign({}, DefaultConfiguration)
customConfig.template = "${{RELEASE_DIFF}}" customConfig.template = "${{RELEASE_DIFF}}"
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v2.8.0', fromTag: 'v2.8.0',
@@ -553,7 +554,7 @@ it('Use exclude labels to not include a PR within a category.', async () => {
} }
] ]
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: '1.0.0',
@@ -1,6 +1,6 @@
{ {
"template": "${{CHANGELOG}}\n${{UNCATEGORIZED}}\n${{IGNORED}}\n${{OWNER}}\n${{REPO}}\n${{FROM_TAG}}\n${{TO_TAG}}\n${{CATEGORIZED_COUNT}}\n${{UNCATEGORIZED_COUNT}}\n${{IGNORED_COUNT}}", "template": "${{CHANGELOG}}\n${{UNCATEGORIZED}}\n${{IGNORED}}\n${{OWNER}}\n${{REPO}}\n${{FROM_TAG}}\n${{TO_TAG}}\n${{RELEASE_DIFF}}\n${{CATEGORIZED_COUNT}}\n${{UNCATEGORIZED_COUNT}}\n${{IGNORED_COUNT}}\n${{CHANGED_FILES}}\n${{ADDITIONS}}\n${{DELETIONS}}\n${{CHANGES}}\n${{COMMITS}}",
"empty_template": "${{OWNER}}\n${{REPO}}\n${{FROM_TAG}}\n${{TO_TAG}}", "empty_template": "${{OWNER}}\n${{REPO}}\n${{FROM_TAG}}\n${{TO_TAG}}\n${{RELEASE_DIFF}}",
"max_pull_requests": 1000, "max_pull_requests": 1000,
"max_back_track_time_days": 1000 "max_back_track_time_days": 1000
} }
Generated Vendored
+76 -26
View File
@@ -42,21 +42,36 @@ 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.filterCommits = exports.Commits = void 0; exports.filterCommits = exports.Commits = exports.DefaultDiffInfo = 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.DefaultDiffInfo = {
changedFiles: 0,
additions: 0,
deletions: 0,
changes: 0,
commits: 0,
commitInfo: []
};
class Commits { class Commits {
constructor(octokit) { constructor(octokit) {
this.octokit = octokit; this.octokit = octokit;
} }
getDiff(owner, repo, base, head) { getDiff(owner, repo, base, head) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const commits = yield this.getDiffRemote(owner, repo, base, head); const diff = yield this.getDiffRemote(owner, repo, base, head);
return this.sortCommits(commits); diff.commitInfo = this.sortCommits(diff.commitInfo);
return diff;
}); });
} }
getDiffRemote(owner, repo, base, head) { getDiffRemote(owner, repo, base, head) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
let changedFilesCount = 0;
let additionCount = 0;
let deletionCount = 0;
let changeCount = 0;
let commitCount = 0;
// Fetch comparisons recursively until we don't find any commits // Fetch comparisons recursively until we don't find any commits
// This is because the GitHub API limits the number of commits returned in a single response. // This is because the GitHub API limits the number of commits returned in a single response.
let commits = []; let commits = [];
@@ -72,11 +87,27 @@ class Commits {
if (compareResult.data.total_commits === 0) { if (compareResult.data.total_commits === 0) {
break; break;
} }
changedFilesCount += (_b = (_a = compareResult.data.files) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
const files = compareResult.data.files;
if (files !== undefined) {
for (const file of files) {
additionCount += file.additions;
deletionCount += file.deletions;
changeCount += file.changes;
}
}
commitCount += compareResult.data.commits.length;
commits = compareResult.data.commits.concat(commits); commits = compareResult.data.commits.concat(commits);
compareHead = `${commits[0].sha}^`; compareHead = `${commits[0].sha}^`;
} }
core.info(`️ Found ${commits.length} commits from the GitHub API for ${owner}/${repo}`); core.info(`️ Found ${commits.length} commits from the GitHub API for ${owner}/${repo}`);
return commits return {
changedFiles: changedFilesCount,
additions: additionCount,
deletions: deletionCount,
changes: changeCount,
commits: commitCount,
commitInfo: commits
.filter(commit => commit.sha) .filter(commit => commit.sha)
.map(commit => { .map(commit => {
var _a, _b; var _a, _b;
@@ -88,7 +119,8 @@ class Commits {
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
}); });
}); })
};
}); });
} }
sortCommits(commits) { sortCommits(commits) {
@@ -718,29 +750,40 @@ class ReleaseNotes {
pull() { pull() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
let mergedPullRequests; let mergedPullRequests;
let diffInfo;
if (!this.options.commitMode) { if (!this.options.commitMode) {
core.startGroup(`🚀 Load pull requests`); core.startGroup(`🚀 Load pull requests`);
mergedPullRequests = yield this.getMergedPullRequests(this.octokit); const [info, prs] = yield this.getMergedPullRequests(this.octokit);
mergedPullRequests = prs;
diffInfo = info;
// define the included PRs within this release as output // define the included PRs within this release as output
core.setOutput('pull_requests', mergedPullRequests core.setOutput('pull_requests', mergedPullRequests
.map(pr => { .map(pr => {
return pr.number; return pr.number;
}) })
.join(',')); .join(','));
core.setOutput('changed_files', diffInfo.changedFiles);
core.setOutput('additions', diffInfo.additions);
core.setOutput('deletions', diffInfo.deletions);
core.setOutput('changes', diffInfo.changes);
core.setOutput('commits', diffInfo.commits);
core.endGroup(); core.endGroup();
} }
else { else {
core.startGroup(`🚀 Load commit history`); core.startGroup(`🚀 Load commit history`);
core.info(`⚠️ Executing experimental commit mode`); core.info(`⚠️ Executing experimental commit mode`);
mergedPullRequests = yield this.generateCommitPRs(this.octokit); const [info, prs] = yield this.generateCommitPRs(this.octokit);
mergedPullRequests = prs;
diffInfo = info;
core.endGroup(); core.endGroup();
} }
if (mergedPullRequests.length === 0) { if (mergedPullRequests.length === 0) {
core.warning(`⚠️ No pull requests found`); core.warning(`⚠️ No pull requests found`);
return null; return (0, transform_1.fillAdditionalPlaceholders)(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)(mergedPullRequests, this.options); const resultChangelog = (0, transform_1.buildChangelog)(diffInfo, mergedPullRequests, this.options);
core.endGroup(); core.endGroup();
return resultChangelog; return resultChangelog;
}); });
@@ -750,27 +793,28 @@ class ReleaseNotes {
const { owner, repo, fromTag, toTag, failOnError } = this.options; const { owner, repo, fromTag, toTag, failOnError } = this.options;
core.info(`️ Comparing ${owner}/${repo} - '${fromTag}...${toTag}'`); core.info(`️ Comparing ${owner}/${repo} - '${fromTag}...${toTag}'`);
const commitsApi = new commits_1.Commits(octokit); const commitsApi = new commits_1.Commits(octokit);
let commits; let diffInfo;
try { try {
commits = yield commitsApi.getDiff(owner, repo, fromTag, toTag); diffInfo = yield commitsApi.getDiff(owner, repo, fromTag, toTag);
} }
catch (error) { catch (error) {
(0, 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 commits_1.DefaultDiffInfo;
} }
if (commits.length === 0) { if (diffInfo.commitInfo.length === 0) {
core.warning(`⚠️ No commits found between - ${fromTag}...${toTag}`); core.warning(`⚠️ No commits found between - ${fromTag}...${toTag}`);
return []; return commits_1.DefaultDiffInfo;
} }
return commits; return diffInfo;
}); });
} }
getMergedPullRequests(octokit) { getMergedPullRequests(octokit) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const { owner, repo, includeOpen, fetchReviewers, configuration } = this.options; const { owner, repo, includeOpen, fetchReviewers, configuration } = this.options;
const commits = yield this.getCommitHistory(octokit); const diffInfo = yield this.getCommitHistory(octokit);
const commits = diffInfo.commitInfo;
if (commits.length === 0) { if (commits.length === 0) {
return []; return [diffInfo, []];
} }
const firstCommit = commits[0]; const firstCommit = commits[0];
const lastCommit = commits[commits.length - 1]; const lastCommit = commits[commits.length - 1];
@@ -832,20 +876,21 @@ class ReleaseNotes {
} }
} }
} }
return finalPrs; return [diffInfo, finalPrs];
}); });
} }
generateCommitPRs(octokit) { generateCommitPRs(octokit) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const { owner, repo, configuration } = this.options; const { owner, repo, configuration } = this.options;
const commits = yield this.getCommitHistory(octokit); const diffInfo = yield this.getCommitHistory(octokit);
const commits = diffInfo.commitInfo;
if (commits.length === 0) { if (commits.length === 0) {
return []; return [diffInfo, []];
} }
const prCommits = (0, 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) { const prs = prCommits.map(function (commit) {
return { return {
number: 0, number: 0,
title: commit.summary, title: commit.summary,
@@ -865,6 +910,7 @@ class ReleaseNotes {
status: 'merged' status: 'merged'
}; };
}); });
return [diffInfo, prs];
}); });
} }
} }
@@ -918,7 +964,6 @@ const rest_1 = __nccwpck_require__(5375);
const releaseNotes_1 = __nccwpck_require__(5882); const releaseNotes_1 = __nccwpck_require__(5882);
const tags_1 = __nccwpck_require__(7532); const tags_1 = __nccwpck_require__(7532);
const utils_1 = __nccwpck_require__(918); const utils_1 = __nccwpck_require__(918);
const transform_1 = __nccwpck_require__(1644);
class ReleaseNotesBuilder { class ReleaseNotesBuilder {
constructor(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen = false, failOnError, ignorePreReleases, fetchReviewers = false, commitMode, configuration) { constructor(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen = false, failOnError, ignorePreReleases, fetchReviewers = false, commitMode, configuration) {
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
@@ -996,9 +1041,7 @@ class ReleaseNotesBuilder {
configuration: this.configuration configuration: this.configuration
}; };
const releaseNotes = new releaseNotes_1.ReleaseNotes(octokit, options); const releaseNotes = new releaseNotes_1.ReleaseNotes(octokit, options);
return ((yield releaseNotes.pull()) || return yield releaseNotes.pull();
(0, transform_1.fillAdditionalPlaceholders)(this.configuration.empty_template ||
configuration_1.DefaultConfiguration.empty_template, options));
}); });
} }
} }
@@ -1364,7 +1407,7 @@ exports.validateTransformer = exports.fillAdditionalPlaceholders = exports.build
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);
function buildChangelog(prs, options) { function buildChangelog(diffInfo, prs, options) {
// sort to target order // sort to target order
const config = options.configuration; const config = options.configuration;
const sort = config.sort || configuration_1.DefaultConfiguration.sort; const sort = config.sort || configuration_1.DefaultConfiguration.sort;
@@ -1546,6 +1589,12 @@ function buildChangelog(prs, options) {
transformedChangelog = transformedChangelog.replace(/\${{UNCATEGORIZED_COUNT}}/g, uncategorizedPrs.length.toString()); transformedChangelog = transformedChangelog.replace(/\${{UNCATEGORIZED_COUNT}}/g, uncategorizedPrs.length.toString());
transformedChangelog = transformedChangelog.replace(/\${{OPEN_COUNT}}/g, openPrs.length.toString()); transformedChangelog = transformedChangelog.replace(/\${{OPEN_COUNT}}/g, openPrs.length.toString());
transformedChangelog = transformedChangelog.replace(/\${{IGNORED_COUNT}}/g, ignoredPrs.length.toString()); transformedChangelog = transformedChangelog.replace(/\${{IGNORED_COUNT}}/g, ignoredPrs.length.toString());
// code change placeholders
transformedChangelog = transformedChangelog.replace(/\${{CHANGED_FILES}}/g, diffInfo.changedFiles.toString());
transformedChangelog = transformedChangelog.replace(/\${{ADDITIONS}}/g, diffInfo.additions.toString());
transformedChangelog = transformedChangelog.replace(/\${{DELETIONS}}/g, diffInfo.deletions.toString());
transformedChangelog = transformedChangelog.replace(/\${{CHANGES}}/g, diffInfo.changes.toString());
transformedChangelog = transformedChangelog.replace(/\${{COMMITS}}/g, diffInfo.commits.toString());
transformedChangelog = fillAdditionalPlaceholders(transformedChangelog, options); transformedChangelog = fillAdditionalPlaceholders(transformedChangelog, options);
core.info(`️ Filled template`); core.info(`️ Filled template`);
return transformedChangelog; return transformedChangelog;
@@ -1553,6 +1602,7 @@ function buildChangelog(prs, options) {
exports.buildChangelog = buildChangelog; exports.buildChangelog = buildChangelog;
function fillAdditionalPlaceholders(text, options) { function fillAdditionalPlaceholders(text, options) {
let transformed = text; let transformed = text;
// repository placeholders
transformed = transformed.replace(/\${{OWNER}}/g, options.owner); transformed = transformed.replace(/\${{OWNER}}/g, options.owner);
transformed = transformed.replace(/\${{REPO}}/g, options.repo); transformed = transformed.replace(/\${{REPO}}/g, options.repo);
transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag); transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag);
Generated Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
+47 -10
View File
@@ -2,6 +2,24 @@ import * as core from '@actions/core'
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest' import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
import moment from 'moment' import moment from 'moment'
export interface DiffInfo {
changedFiles: number
additions: number
deletions: number
changes: number
commits: number
commitInfo: CommitInfo[]
}
export const DefaultDiffInfo: DiffInfo = {
changedFiles: 0,
additions: 0,
deletions: 0,
changes: 0,
commits: 0,
commitInfo: []
}
export interface CommitInfo { export interface CommitInfo {
sha: string sha: string
summary: string summary: string
@@ -18,14 +36,10 @@ export class Commits {
repo: string, repo: string,
base: string, base: string,
head: string head: string
): Promise<CommitInfo[]> { ): Promise<DiffInfo> {
const commits: CommitInfo[] = await this.getDiffRemote( const diff: DiffInfo = await this.getDiffRemote(owner, repo, base, head)
owner, diff.commitInfo = this.sortCommits(diff.commitInfo)
repo, return diff
base,
head
)
return this.sortCommits(commits)
} }
private async getDiffRemote( private async getDiffRemote(
@@ -33,7 +47,13 @@ export class Commits {
repo: string, repo: string,
base: string, base: string,
head: string head: string
): Promise<CommitInfo[]> { ): Promise<DiffInfo> {
let changedFilesCount = 0
let additionCount = 0
let deletionCount = 0
let changeCount = 0
let commitCount = 0
// Fetch comparisons recursively until we don't find any commits // Fetch comparisons recursively until we don't find any commits
// This is because the GitHub API limits the number of commits returned in a single response. // This is because the GitHub API limits the number of commits returned in a single response.
let commits: RestEndpointMethodTypes['repos']['compareCommits']['response']['data']['commits'] = let commits: RestEndpointMethodTypes['repos']['compareCommits']['response']['data']['commits'] =
@@ -50,6 +70,16 @@ export class Commits {
if (compareResult.data.total_commits === 0) { if (compareResult.data.total_commits === 0) {
break break
} }
changedFilesCount += compareResult.data.files?.length ?? 0
const files = compareResult.data.files
if (files !== undefined) {
for (const file of files) {
additionCount += file.additions
deletionCount += file.deletions
changeCount += file.changes
}
}
commitCount += compareResult.data.commits.length
commits = compareResult.data.commits.concat(commits) commits = compareResult.data.commits.concat(commits)
compareHead = `${commits[0].sha}^` compareHead = `${commits[0].sha}^`
} }
@@ -58,7 +88,13 @@ export class Commits {
`️ Found ${commits.length} commits from the GitHub API for ${owner}/${repo}` `️ Found ${commits.length} commits from the GitHub API for ${owner}/${repo}`
) )
return commits return {
changedFiles: changedFilesCount,
additions: additionCount,
deletions: deletionCount,
changes: changeCount,
commits: commitCount,
commitInfo: commits
.filter(commit => commit.sha) .filter(commit => commit.sha)
.map(commit => ({ .map(commit => ({
sha: commit.sha || '', sha: commit.sha || '',
@@ -69,6 +105,7 @@ export class Commits {
prNumber: undefined prNumber: undefined
})) }))
} }
}
private sortCommits(commits: CommitInfo[]): CommitInfo[] { private sortCommits(commits: CommitInfo[]): CommitInfo[] {
const commitsResult = [] const commitsResult = []
+45 -22
View File
@@ -1,9 +1,9 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import {CommitInfo, Commits, filterCommits} from './commits' 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} from './transform' import {buildChangelog, fillAdditionalPlaceholders} from './transform'
import {failOrError} from './utils' import {failOrError} from './utils'
export interface ReleaseNotesOptions { export interface ReleaseNotesOptions {
@@ -21,11 +21,15 @@ export interface ReleaseNotesOptions {
export class ReleaseNotes { export class ReleaseNotes {
constructor(private octokit: Octokit, private options: ReleaseNotesOptions) {} constructor(private octokit: Octokit, private options: ReleaseNotesOptions) {}
async pull(): Promise<string | null> { async pull(): Promise<string> {
let mergedPullRequests: PullRequestInfo[] let mergedPullRequests: PullRequestInfo[]
let diffInfo: DiffInfo
if (!this.options.commitMode) { if (!this.options.commitMode) {
core.startGroup(`🚀 Load pull requests`) core.startGroup(`🚀 Load pull requests`)
mergedPullRequests = await this.getMergedPullRequests(this.octokit)
const [info, prs] = await this.getMergedPullRequests(this.octokit)
mergedPullRequests = prs
diffInfo = info
// define the included PRs within this release as output // define the included PRs within this release as output
core.setOutput( core.setOutput(
@@ -37,57 +41,74 @@ export class ReleaseNotes {
.join(',') .join(',')
) )
core.setOutput('changed_files', diffInfo.changedFiles)
core.setOutput('additions', diffInfo.additions)
core.setOutput('deletions', diffInfo.deletions)
core.setOutput('changes', diffInfo.changes)
core.setOutput('commits', diffInfo.commits)
core.endGroup() core.endGroup()
} else { } else {
core.startGroup(`🚀 Load commit history`) core.startGroup(`🚀 Load commit history`)
core.info(`⚠️ Executing experimental commit mode`) core.info(`⚠️ Executing experimental commit mode`)
mergedPullRequests = await this.generateCommitPRs(this.octokit) const [info, prs] = await this.generateCommitPRs(this.octokit)
mergedPullRequests = prs
diffInfo = info
core.endGroup() core.endGroup()
} }
if (mergedPullRequests.length === 0) { if (mergedPullRequests.length === 0) {
core.warning(`⚠️ No pull requests found`) core.warning(`⚠️ No pull requests found`)
return null return fillAdditionalPlaceholders(
this.options.configuration.empty_template ||
DefaultConfiguration.empty_template,
this.options
)
} }
core.startGroup('📦 Build changelog') core.startGroup('📦 Build changelog')
const resultChangelog = buildChangelog(mergedPullRequests, this.options) const resultChangelog = buildChangelog(
diffInfo,
mergedPullRequests,
this.options
)
core.endGroup() core.endGroup()
return resultChangelog return resultChangelog
} }
private async getCommitHistory(octokit: Octokit): Promise<CommitInfo[]> { private async getCommitHistory(octokit: Octokit): Promise<DiffInfo> {
const {owner, repo, fromTag, toTag, failOnError} = this.options const {owner, repo, fromTag, toTag, failOnError} = this.options
core.info(`️ Comparing ${owner}/${repo} - '${fromTag}...${toTag}'`) core.info(`️ Comparing ${owner}/${repo} - '${fromTag}...${toTag}'`)
const commitsApi = new Commits(octokit) const commitsApi = new Commits(octokit)
let commits: CommitInfo[] let diffInfo: DiffInfo
try { try {
commits = await commitsApi.getDiff(owner, repo, fromTag, toTag) diffInfo = await commitsApi.getDiff(owner, repo, fromTag, toTag)
} catch (error) { } catch (error) {
failOrError( failOrError(
`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, `💥 Failed to retrieve - Invalid tag? - Because of: ${error}`,
failOnError failOnError
) )
return [] return DefaultDiffInfo
} }
if (commits.length === 0) { if (diffInfo.commitInfo.length === 0) {
core.warning(`⚠️ No commits found between - ${fromTag}...${toTag}`) core.warning(`⚠️ No commits found between - ${fromTag}...${toTag}`)
return [] return DefaultDiffInfo
} }
return commits return diffInfo
} }
private async getMergedPullRequests( private async getMergedPullRequests(
octokit: Octokit octokit: Octokit
): Promise<PullRequestInfo[]> { ): Promise<[DiffInfo, PullRequestInfo[]]> {
const {owner, repo, includeOpen, fetchReviewers, configuration} = const {owner, repo, includeOpen, fetchReviewers, configuration} =
this.options this.options
const commits = await this.getCommitHistory(octokit) const diffInfo = await this.getCommitHistory(octokit)
const commits = diffInfo.commitInfo
if (commits.length === 0) { if (commits.length === 0) {
return [] return [diffInfo, []]
} }
const firstCommit = commits[0] const firstCommit = commits[0]
@@ -193,17 +214,18 @@ export class ReleaseNotes {
} }
} }
return finalPrs return [diffInfo, finalPrs]
} }
private async generateCommitPRs( private async generateCommitPRs(
octokit: Octokit octokit: Octokit
): Promise<PullRequestInfo[]> { ): Promise<[DiffInfo, PullRequestInfo[]]> {
const {owner, repo, configuration} = this.options const {owner, repo, configuration} = this.options
const commits = await this.getCommitHistory(octokit) const diffInfo = await this.getCommitHistory(octokit)
const commits = diffInfo.commitInfo
if (commits.length === 0) { if (commits.length === 0) {
return [] return [diffInfo, []]
} }
const prCommits = filterCommits( const prCommits = filterCommits(
@@ -214,7 +236,7 @@ export class ReleaseNotes {
core.info(`️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`) core.info(`️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`)
return prCommits.map(function (commit): PullRequestInfo { const prs = prCommits.map(function (commit): PullRequestInfo {
return { return {
number: 0, number: 0,
title: commit.summary, title: commit.summary,
@@ -234,5 +256,6 @@ export class ReleaseNotes {
status: 'merged' status: 'merged'
} }
}) })
return [diffInfo, prs]
} }
} }
+1 -9
View File
@@ -4,7 +4,6 @@ import {Octokit} from '@octokit/rest'
import {ReleaseNotes} from './releaseNotes' import {ReleaseNotes} from './releaseNotes'
import {Tags} from './tags' import {Tags} from './tags'
import {failOrError} from './utils' import {failOrError} from './utils'
import {fillAdditionalPlaceholders} from './transform'
export class ReleaseNotesBuilder { export class ReleaseNotesBuilder {
constructor( constructor(
@@ -98,13 +97,6 @@ export class ReleaseNotesBuilder {
} }
const releaseNotes = new ReleaseNotes(octokit, options) const releaseNotes = new ReleaseNotes(octokit, options)
return ( return await releaseNotes.pull()
(await releaseNotes.pull()) ||
fillAdditionalPlaceholders(
this.configuration.empty_template ||
DefaultConfiguration.empty_template,
options
)
)
} }
} }
+24
View File
@@ -7,8 +7,10 @@ import {
} from './configuration' } from './configuration'
import {PullRequestInfo, sortPullRequests} from './pullRequests' import {PullRequestInfo, sortPullRequests} from './pullRequests'
import {ReleaseNotesOptions} from './releaseNotes' import {ReleaseNotesOptions} from './releaseNotes'
import {DiffInfo} from './commits'
export function buildChangelog( export function buildChangelog(
diffInfo: DiffInfo,
prs: PullRequestInfo[], prs: PullRequestInfo[],
options: ReleaseNotesOptions options: ReleaseNotesOptions
): string { ): string {
@@ -272,6 +274,27 @@ export function buildChangelog(
/\${{IGNORED_COUNT}}/g, /\${{IGNORED_COUNT}}/g,
ignoredPrs.length.toString() ignoredPrs.length.toString()
) )
// code change placeholders
transformedChangelog = transformedChangelog.replace(
/\${{CHANGED_FILES}}/g,
diffInfo.changedFiles.toString()
)
transformedChangelog = transformedChangelog.replace(
/\${{ADDITIONS}}/g,
diffInfo.additions.toString()
)
transformedChangelog = transformedChangelog.replace(
/\${{DELETIONS}}/g,
diffInfo.deletions.toString()
)
transformedChangelog = transformedChangelog.replace(
/\${{CHANGES}}/g,
diffInfo.changes.toString()
)
transformedChangelog = transformedChangelog.replace(
/\${{COMMITS}}/g,
diffInfo.commits.toString()
)
transformedChangelog = fillAdditionalPlaceholders( transformedChangelog = fillAdditionalPlaceholders(
transformedChangelog, transformedChangelog,
options options
@@ -286,6 +309,7 @@ export function fillAdditionalPlaceholders(
options: ReleaseNotesOptions options: ReleaseNotesOptions
): string { ): string {
let transformed = text let transformed = text
// repository placeholders
transformed = transformed.replace(/\${{OWNER}}/g, options.owner) transformed = transformed.replace(/\${{OWNER}}/g, options.owner)
transformed = transformed.replace(/\${{REPO}}/g, options.repo) transformed = transformed.replace(/\${{REPO}}/g, options.repo)
transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag) transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag)