- introduce capability of the action running 2 split

- first collect all pull requests and export to environment
  - second take exported data and continue generation of changelogs (makes it cheaper, by only collecting PRs once)
This commit is contained in:
Mike Penz
2023-05-26 13:41:59 +00:00
committed by GitHub
parent 66470e5f14
commit 0a80bc9a3b
12 changed files with 515 additions and 240 deletions
+28 -4
View File
@@ -113,6 +113,19 @@ jobs:
run: echo "CHANGELOG" run: echo "CHANGELOG"
# Showcases the capability to generate the changelog for an external repository provided # Showcases the capability to generate the changelog for an external repository provided
# Showcase ability to only fetch data first, and then continue with exported data later
- name: "External Repo Configuration Collect Report"
id: external_changelog_collect
uses: ./
with:
owner: "mikepenz"
repo: "MaterialDrawer"
fromTag: "v8.1.0"
toTag: "v8.1.6"
token: ${{ secrets.PERSONAL_TOKEN }}
exportCollected: true
exportOnly: true
- name: "External Repo Configuration" - name: "External Repo Configuration"
id: external_changelog id: external_changelog
uses: ./ uses: ./
@@ -120,14 +133,25 @@ jobs:
configuration: "configs/configuration_complex.json" configuration: "configs/configuration_complex.json"
owner: "mikepenz" owner: "mikepenz"
repo: "MaterialDrawer" repo: "MaterialDrawer"
fromTag: "v8.1.0"
toTag: "v8.1.6" - name: "External Repo Configuration Second"
token: ${{ secrets.PERSONAL_TOKEN }} id: external_changelog_second
uses: ./
with:
configuration: "configs/configuration.json"
owner: "mikepenz"
repo: "MaterialDrawer"
- name: Echo External Repo Configuration Changelog - name: Echo External Repo Configuration Changelog
env: env:
CHANGELOG: ${{ steps.external_changelog.outputs.changelog }} CHANGELOG: ${{ steps.external_changelog.outputs.changelog }}
run: echo "$CHANGELOG" CHANGELOG_SECOND: ${{ steps.external_changelog_second.outputs.changelog }}
run: |
echor "First:"
echo "$CHANGELOG"
echor "Second:"
echo "$CHANGELOG_SECOND"
release: release:
if: startsWith(github.ref, 'refs/tags/') if: startsWith(github.ref, 'refs/tags/')
+42 -14
View File
@@ -19,7 +19,9 @@ it('Should match generated changelog (unspecified fromTag)', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information false, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
false, false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration configuration
) )
@@ -49,7 +51,9 @@ it('Should match generated changelog (unspecified tags)', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information false, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
false, false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration configuration
) )
@@ -74,7 +78,9 @@ it('Should use empty placeholder', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information false, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
false, false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration configuration
) )
@@ -99,7 +105,9 @@ it('Should fill empty placeholders', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information false, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
false, false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration configuration
) )
@@ -126,7 +134,9 @@ it('Should fill `template` placeholders', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information false, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
false, false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration configuration
) )
@@ -153,7 +163,9 @@ it('Should fill `template` placeholders, ignore', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information false, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
false, false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration configuration
) )
@@ -180,7 +192,9 @@ it('Uncategorized category', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information false, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
false, false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration configuration
) )
@@ -207,7 +221,9 @@ it('Verify commit based changelog', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information false, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
true, false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration configuration
) )
@@ -234,7 +250,9 @@ it('Verify commit based changelog, with emoji categorisation', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information false, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
true, false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration configuration
) )
@@ -261,7 +279,9 @@ it('Verify default inclusion of open PRs', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information false, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
false, // commitMode false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration // configuration configuration // configuration
) )
@@ -288,7 +308,9 @@ it('Verify custom categorisation of open PRs', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information false, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
false, // commitMode false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration // configuration configuration // configuration
) )
@@ -315,7 +337,9 @@ it('Verify reviewers who approved are fetched and also release information', asy
true, // enable to fetch reviewers true, // enable to fetch reviewers
true, // enable to fetch tag release information true, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
false, // commitMode false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration // configuration configuration // configuration
) )
@@ -343,7 +367,9 @@ it('Fetch release information', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
true, // enable to fetch tag release information true, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
false, // commitMode false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration // configuration configuration // configuration
) )
@@ -369,7 +395,9 @@ it('Fetch release information for non existing tag / release', async () => {
false, // enable to fetch reviewers false, // enable to fetch reviewers
true, // enable to fetch tag release information true, // enable to fetch tag release information
false, // enable to fetch reviews false, // enable to fetch reviews
false, // commitMode false, // enable commitMode
false, // enable exportCollected
false, // enable exportOnly
configuration // configuration configuration // configuration
) )
+20 -20
View File
@@ -25,9 +25,9 @@ it('Should have empty changelog (tags)', async () => {
fetchReviews: false, fetchReviews: false,
commitMode: false, commitMode: false,
configuration configuration
}) }, false, false)
const changeLog = buildChangelog(data.diffInfo, data.mergedPullRequests, data.options) const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual('- no changes') expect(changeLog).toStrictEqual('- no changes')
}) })
@@ -46,9 +46,9 @@ it('Should match generated changelog (tags)', async () => {
fetchReviews: false, fetchReviews: false,
commitMode: false, commitMode: false,
configuration configuration
}) }, false, false)
const changeLog = buildChangelog(data.diffInfo, data.mergedPullRequests, data.options) const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual(`## 🧪 Tests expect(changeLog).toStrictEqual(`## 🧪 Tests
@@ -72,9 +72,9 @@ it('Should match generated changelog (refs)', async () => {
fetchReviews: false, fetchReviews: false,
commitMode: false, commitMode: false,
configuration configuration
}) }, false, false)
const changeLog = buildChangelog(data.diffInfo, data.mergedPullRequests, data.options) const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual(`## 🧪 Tests expect(changeLog).toStrictEqual(`## 🧪 Tests
@@ -106,9 +106,9 @@ it('Should match generated changelog and replace all occurrences (refs)', async
fetchReviews: false, fetchReviews: false,
commitMode: false, commitMode: false,
configuration configuration
}) }, false, false)
const changeLog = buildChangelog(data.diffInfo, data.mergedPullRequests, data.options) const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual(`## 🧪 Tests expect(changeLog).toStrictEqual(`## 🧪 Tests
@@ -142,9 +142,9 @@ it('Should match ordered ASC', async () => {
fetchReviews: false, fetchReviews: false,
commitMode: false, commitMode: false,
configuration configuration
}) }, false, false)
const changeLog = buildChangelog(data.diffInfo, data.mergedPullRequests, data.options) const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual(`## 🚀 Features\n\n22\n24\n25\n26\n28\n\n## 🐛 Fixes\n\n23\n\n`) expect(changeLog).toStrictEqual(`## 🚀 Features\n\n22\n24\n25\n26\n28\n\n## 🐛 Fixes\n\n23\n\n`)
}) })
@@ -163,9 +163,9 @@ it('Should match ordered DESC', async () => {
fetchReviews: false, fetchReviews: false,
commitMode: false, commitMode: false,
configuration configuration
}) }, false, false)
const changeLog = buildChangelog(data.diffInfo, data.mergedPullRequests, data.options) const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual(`## 🚀 Features\n\n28\n26\n25\n24\n22\n\n## 🐛 Fixes\n\n23\n\n`) expect(changeLog).toStrictEqual(`## 🚀 Features\n\n28\n26\n25\n24\n22\n\n## 🐛 Fixes\n\n23\n\n`)
}) })
@@ -184,9 +184,9 @@ it('Should match ordered by title ASC', async () => {
fetchReviews: false, fetchReviews: false,
commitMode: false, commitMode: false,
configuration configuration
}) }, false, false)
const changeLog = buildChangelog(data.diffInfo, data.mergedPullRequests, data.options) const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual( expect(changeLog).toStrictEqual(
`## 🚀 Features\n\nEnhanced action logs\nImprove README\nImproved configuration failure handling\nImproved defaults if no configuration is provided\nIntroduce additional placeholders [milestone, labels, assignees, reviewers]\n\n## 🐛 Fixes\n\nImproved handling for non existing tags\n\n` `## 🚀 Features\n\nEnhanced action logs\nImprove README\nImproved configuration failure handling\nImproved defaults if no configuration is provided\nIntroduce additional placeholders [milestone, labels, assignees, reviewers]\n\n## 🐛 Fixes\n\nImproved handling for non existing tags\n\n`
@@ -207,9 +207,9 @@ it('Should match ordered by title DESC', async () => {
fetchReviews: false, fetchReviews: false,
commitMode: false, commitMode: false,
configuration configuration
}) }, false, false)
const changeLog = buildChangelog(data.diffInfo, data.mergedPullRequests, data.options) const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual( expect(changeLog).toStrictEqual(
`## 🚀 Features\n\nIntroduce additional placeholders [milestone, labels, assignees, reviewers]\nImproved defaults if no configuration is provided\nImproved configuration failure handling\nImprove README\nEnhanced action logs\n\n## 🐛 Fixes\n\nImproved handling for non existing tags\n\n` `## 🚀 Features\n\nIntroduce additional placeholders [milestone, labels, assignees, reviewers]\nImproved defaults if no configuration is provided\nImproved configuration failure handling\nImprove README\nEnhanced action logs\n\n## 🐛 Fixes\n\nImproved handling for non existing tags\n\n`
@@ -230,9 +230,9 @@ it('Should ignore PRs not merged into develop branch', async () => {
fetchReviews: false, fetchReviews: false,
commitMode: false, commitMode: false,
configuration configuration
}) }, false, false)
const changeLog = buildChangelog(data.diffInfo, data.mergedPullRequests, data.options) const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual(`150\n\n`) expect(changeLog).toStrictEqual(`150\n\n`)
}) })
@@ -251,9 +251,9 @@ it('Should ignore PRs not merged into main branch', async () => {
fetchReviews: false, fetchReviews: false,
commitMode: false, commitMode: false,
configuration configuration
}) }, false, false)
const changeLog = buildChangelog(data.diffInfo, data.mergedPullRequests, data.options) const changeLog = buildChangelog(data!.diffInfo, data!.mergedPullRequests, data!.options)
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual(`153\n\n`) expect(changeLog).toStrictEqual(`153\n\n`)
}) })
+6
View File
@@ -40,6 +40,12 @@ inputs:
commitMode: commitMode:
description: 'Enables a `light` commit based mode. This mode generates changelogs based on the commits. Please note that this is not officially supported, and lacks a lot of features only possible with PRs.' description: 'Enables a `light` commit based mode. This mode generates changelogs based on the commits. Please note that this is not officially supported, and lacks a lot of features only possible with PRs.'
default: "false" default: "false"
exportCollected:
description: 'Enables the export of all collected PR information to an environment variable'
default: "false"
exportOnly:
description: 'If enabled, the action will only collect the data and terminate afterwards. Data can then be consumed by steps afterwards'
default: "false"
outputFile: outputFile:
description: 'If defined, the changelog will get written to this file. (relative to the checkout dir)' description: 'If defined, the changelog will get written to this file. (relative to the checkout dir)'
token: token:
Generated Vendored
+119 -18
View File
@@ -186,7 +186,7 @@ class Commits {
mergeCommitSha: commit.sha, mergeCommitSha: commit.sha,
author: commit.author || '', author: commit.author || '',
repoName: '', repoName: '',
labels: new Set(), labels: [],
milestone: '', milestone: '',
body: commit.message || '', body: commit.message || '',
assignees: [], assignees: [],
@@ -487,7 +487,9 @@ function run() {
const fetchReleaseInformation = core.getInput('fetchReleaseInformation') === 'true'; const fetchReleaseInformation = core.getInput('fetchReleaseInformation') === 'true';
const fetchReviews = core.getInput('fetchReviews') === 'true'; const fetchReviews = core.getInput('fetchReviews') === 'true';
const commitMode = core.getInput('commitMode') === 'true'; const commitMode = core.getInput('commitMode') === 'true';
const result = yield new releaseNotesBuilder_1.ReleaseNotesBuilder(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen, failOnError, ignorePreReleases, fetchReviewers, fetchReleaseInformation, fetchReviews, commitMode, configuration).build(); const exportCollected = core.getInput('exportCollected') === 'true';
const exportOnly = core.getInput('exportOnly') === 'true';
const result = yield new releaseNotesBuilder_1.ReleaseNotesBuilder(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen, failOnError, ignorePreReleases, fetchReviewers, fetchReleaseInformation, fetchReviews, commitMode, exportCollected, exportOnly, configuration).build();
core.setOutput('changelog', result); core.setOutput('changelog', result);
// write the result in changelog to file if possible // write the result in changelog to file if possible
const outputFile = core.getInput('outputFile'); const outputFile = core.getInput('outputFile');
@@ -873,7 +875,7 @@ function retrieveProperty(pr, property, useCase) {
exports.retrieveProperty = retrieveProperty; exports.retrieveProperty = retrieveProperty;
// helper function to add a special open label to prs not merged. // helper function to add a special open label to prs not merged.
function attachSpeciaLabels(status, labels) { function attachSpeciaLabels(status, labels) {
labels.add(`--rcba-${status}`); labels.push(`--rcba-${status}`);
return labels; return labels;
} }
const mapPullRequest = (pr, status = 'open') => { const mapPullRequest = (pr, status = 'open') => {
@@ -889,7 +891,7 @@ const mapPullRequest = (pr, status = 'open') => {
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,
labels: attachSpeciaLabels(status, new Set(((_b = pr.labels) === null || _b === void 0 ? void 0 : _b.map(lbl => { var _a; return ((_a = lbl.name) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase('en')) || ''; })) || [])), labels: attachSpeciaLabels(status, ((_b = pr.labels) === null || _b === void 0 ? void 0 : _b.map(lbl => { var _a; return ((_a = lbl.name) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase('en')) || ''; })) || []),
milestone: ((_c = pr.milestone) === null || _c === void 0 ? void 0 : _c.title) || '', milestone: ((_c = pr.milestone) === null || _c === void 0 ? void 0 : _c.title) || '',
body: pr.body || '', body: pr.body || '',
assignees: ((_d = pr.assignees) === null || _d === void 0 ? void 0 : _d.map(asignee => (asignee === null || asignee === void 0 ? void 0 : asignee.login) || '')) || [], assignees: ((_d = pr.assignees) === null || _d === void 0 ? void 0 : _d.map(asignee => (asignee === null || asignee === void 0 ? void 0 : asignee.login) || '')) || [],
@@ -1087,7 +1089,7 @@ const pullRequests_1 = __nccwpck_require__(4217);
const commits_1 = __nccwpck_require__(3916); const commits_1 = __nccwpck_require__(3916);
const transform_1 = __nccwpck_require__(1644); const transform_1 = __nccwpck_require__(1644);
class ReleaseNotesBuilder { class ReleaseNotesBuilder {
constructor(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen = false, failOnError, ignorePreReleases, fetchReviewers = false, fetchReleaseInformation = false, fetchReviews = false, commitMode, configuration) { constructor(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen = false, failOnError, ignorePreReleases, fetchReviewers = false, fetchReleaseInformation = false, fetchReviews = false, commitMode = false, exportCollected = false, exportOnly = false, configuration) {
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
this.token = token; this.token = token;
this.repositoryPath = repositoryPath; this.repositoryPath = repositoryPath;
@@ -1102,10 +1104,14 @@ class ReleaseNotesBuilder {
this.fetchReleaseInformation = fetchReleaseInformation; this.fetchReleaseInformation = fetchReleaseInformation;
this.fetchReviews = fetchReviews; this.fetchReviews = fetchReviews;
this.commitMode = commitMode; this.commitMode = commitMode;
this.exportCollected = exportCollected;
this.exportOnly = exportOnly;
this.configuration = configuration; this.configuration = configuration;
} }
build() { build() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
let releaseNotesData = (0, utils_1.checkExportedData)();
if (releaseNotesData == null) {
if (!this.owner) { if (!this.owner) {
(0, 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;
@@ -1187,13 +1193,54 @@ class ReleaseNotesBuilder {
commitMode: this.commitMode, commitMode: this.commitMode,
configuration: this.configuration configuration: this.configuration
}; };
const releaseNotesData = yield pullData(octokit, options); releaseNotesData = yield pullData(octokit, options, this.exportCollected, this.exportOnly);
}
else {
core.info(`️ Retrieved previously exported collected data`);
// merge input with options (in case some data was updated)
const diffInfo = releaseNotesData.diffInfo;
const mergedPullRequests = releaseNotesData.mergedPullRequests;
const orgOptions = releaseNotesData.options;
// merge fromTag info with provided info || otherwise use cached info
const fromTag = orgOptions.fromTag;
if (this.fromTag != null) {
fromTag.name = this.fromTag;
}
const toTag = orgOptions.toTag;
if (this.toTag != null) {
toTag.name = this.toTag;
}
// merge provided values with previous options (prefer provided)
const options = {
owner: this.owner || orgOptions.owner,
repo: this.repo || orgOptions.repo,
fromTag,
toTag,
includeOpen: this.includeOpen || orgOptions.includeOpen,
failOnError: this.failOnError || orgOptions.failOnError,
fetchReviewers: this.fetchReviewers || orgOptions.fetchReviewers,
fetchReleaseInformation: this.fetchReleaseInformation || orgOptions.fetchReleaseInformation,
fetchReviews: this.fetchReviews || orgOptions.fetchReviews,
commitMode: this.commitMode || orgOptions.commitMode,
configuration: this.configuration || orgOptions.configuration
};
releaseNotesData = {
diffInfo,
mergedPullRequests,
options
};
}
if (releaseNotesData != null) {
return (0, transform_1.buildChangelog)(releaseNotesData.diffInfo, releaseNotesData.mergedPullRequests, releaseNotesData.options); return (0, transform_1.buildChangelog)(releaseNotesData.diffInfo, releaseNotesData.mergedPullRequests, releaseNotesData.options);
}
else {
return null;
}
}); });
} }
} }
exports.ReleaseNotesBuilder = ReleaseNotesBuilder; exports.ReleaseNotesBuilder = ReleaseNotesBuilder;
function pullData(octokit, options) { function pullData(octokit, options, exportCollected, exportOnly) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
let mergedPullRequests; let mergedPullRequests;
let diffInfo; let diffInfo;
@@ -1223,12 +1270,18 @@ function pullData(octokit, options) {
core.setOutput('deletions', diffInfo.deletions); core.setOutput('deletions', diffInfo.deletions);
core.setOutput('changes', diffInfo.changes); core.setOutput('changes', diffInfo.changes);
core.setOutput('commits', diffInfo.commits); core.setOutput('commits', diffInfo.commits);
const collectAndExport = true; if (exportCollected) {
if (collectAndExport) {
core.info('📦 Exporting collected data'); core.info('📦 Exporting collected data');
core.exportVariable('_diffInfo', JSON.stringify(diffInfo)); core.exportVariable(`RCBA_EXPORT_diffInfo`, JSON.stringify(diffInfo));
core.exportVariable('_mergedPullRequests', JSON.stringify(mergedPullRequests)); //fs.writeFileSync(path.resolve('diffInfo.json'), JSON.stringify(diffInfo))
core.exportVariable('_options', JSON.stringify(options)); core.exportVariable(`RCBA_EXPORT_mergedPullRequests`, JSON.stringify(mergedPullRequests));
//fs.writeFileSync(path.resolve('mergedPullRequests.json'), JSON.stringify(mergedPullRequests))
core.exportVariable(`RCBA_EXPORT_options`, JSON.stringify(options));
//fs.writeFileSync(path.resolve('options.json'), JSON.stringify(options))
if (exportOnly) {
core.endGroup();
return null;
}
} }
core.endGroup(); core.endGroup();
return { return {
@@ -1688,7 +1741,7 @@ function buildChangelog(diffInfo, prs, options) {
const extracted = extractValues(pr, extractor, 'label_extractor'); const extracted = extractValues(pr, extractor, 'label_extractor');
if (extracted !== null) { if (extracted !== null) {
for (const label of extracted) { for (const label of extracted) {
pr.labels.add(label); pr.labels.push(label);
} }
if (core.isDebug()) { if (core.isDebug()) {
core.debug(` Extracted the following labels (${JSON.stringify(extracted)}) for PR ${pr.number}`); core.debug(` Extracted the following labels (${JSON.stringify(extracted)}) for PR ${pr.number}`);
@@ -1723,7 +1776,7 @@ function buildChangelog(diffInfo, prs, options) {
const uncategorizedPrs = []; const uncategorizedPrs = [];
// bring elements in order // bring elements in order
for (const [pr, body] of transformedMap) { for (const [pr, body] of transformedMap) {
if ((0, utils_1.haveCommonElements)(ignoredLabels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) { if ((0, utils_1.haveCommonElementsArr)(ignoredLabels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
ignoredPrs.push(body); ignoredPrs.push(body);
continue; continue;
} }
@@ -1735,7 +1788,7 @@ function buildChangelog(diffInfo, prs, options) {
let matched = false; // check if we matched within the given category let matched = false; // check if we matched within the given category
// check if any exclude label matches // check if any exclude label matches
if (category.exclude_labels !== undefined) { if (category.exclude_labels !== undefined) {
if ((0, utils_1.haveCommonElements)(category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) { if ((0, utils_1.haveCommonElementsArr)(category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels)) {
if (core.isDebug()) { if (core.isDebug()) {
const excludeLabels = JSON.stringify(category.exclude_labels); const excludeLabels = JSON.stringify(category.exclude_labels);
core.debug(` PR ${pr.number} with labels: ${pr.labels} excluded from category via exclude label: ${excludeLabels}`); core.debug(` PR ${pr.number} with labels: ${pr.labels} excluded from category via exclude label: ${excludeLabels}`);
@@ -1747,7 +1800,7 @@ function buildChangelog(diffInfo, prs, options) {
// validate for an exhaustive match (e.g. every provided rule applies) // validate for an exhaustive match (e.g. every provided rule applies)
if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) { if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) {
if (category.labels !== undefined) { if (category.labels !== undefined) {
matched = (0, utils_1.haveEveryElements)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels); matched = (0, utils_1.haveEveryElementsArr)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels);
} }
let exhaustive_rules = true; let exhaustive_rules = true;
if (category.exhaustive_rules !== undefined) { if (category.exhaustive_rules !== undefined) {
@@ -1761,7 +1814,7 @@ function buildChangelog(diffInfo, prs, options) {
// if not exhaustive, do individual matches // if not exhaustive, do individual matches
if (category.labels !== undefined) { if (category.labels !== undefined) {
// check if either any of the labels applies // check if either any of the labels applies
matched = (0, utils_1.haveCommonElements)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels); matched = (0, utils_1.haveCommonElementsArr)(category.labels.map(lbl => lbl.toLocaleLowerCase('en')), pr.labels);
} }
let exhaustive_rules = false; let exhaustive_rules = false;
if (category.exhaustive_rules !== undefined) { if (category.exhaustive_rules !== undefined) {
@@ -2108,12 +2161,16 @@ var __importStar = (this && this.__importStar) || function (mod) {
__setModuleDefault(result, mod); __setModuleDefault(result, mod);
return result; return result;
}; };
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.haveEveryElements = exports.haveCommonElements = exports.createOrSet = exports.writeOutput = exports.directoryExistsSync = exports.mergeConfiguration = exports.parseConfiguration = exports.resolveConfiguration = exports.failOrError = exports.retrieveRepositoryPath = void 0; exports.haveEveryElementsArr = exports.haveEveryElements = exports.haveCommonElementsArr = exports.haveCommonElements = exports.createOrSet = exports.writeOutput = exports.directoryExistsSync = exports.mergeConfiguration = exports.parseConfiguration = exports.resolveConfiguration = exports.checkExportedData = exports.failOrError = exports.retrieveRepositoryPath = void 0;
const core = __importStar(__nccwpck_require__(2186)); const core = __importStar(__nccwpck_require__(2186));
const fs = __importStar(__nccwpck_require__(7147)); const fs = __importStar(__nccwpck_require__(7147));
const path = __importStar(__nccwpck_require__(1017)); const path = __importStar(__nccwpck_require__(1017));
const configuration_1 = __nccwpck_require__(5527); const configuration_1 = __nccwpck_require__(5527);
const moment_1 = __importDefault(__nccwpck_require__(9623));
/** /**
* Resolves the repository path, relatively to the GITHUB_WORKSPACE * Resolves the repository path, relatively to the GITHUB_WORKSPACE
*/ */
@@ -2144,6 +2201,42 @@ function failOrError(message, failOnError) {
} }
} }
exports.failOrError = failOrError; exports.failOrError = failOrError;
/**
* Retrieves the exported information from a previous run of the `release-changelog-builder-action`.
* If available, return a [ReleaseNotesData].
*/
function checkExportedData() {
const rawDiffInfo = process.env[`RCBA_EXPORT_diffInfo`];
const rawMergedPullRequests = process.env[`RCBA_EXPORT_mergedPullRequests`];
const rawOptions = process.env[`RCBA_EXPORT_options`];
if (rawDiffInfo && rawMergedPullRequests && rawOptions) {
const diffInfo = JSON.parse(rawDiffInfo);
const mergedPullRequests = JSON.parse(rawMergedPullRequests);
for (const pr of mergedPullRequests) {
pr.createdAt = (0, moment_1.default)(pr.createdAt);
if (pr.mergedAt) {
pr.mergedAt = (0, moment_1.default)(pr.mergedAt);
}
if (pr.reviews) {
for (const review of pr.reviews) {
if (review.submittedAt) {
review.submittedAt = (0, moment_1.default)(review.submittedAt);
}
}
}
}
const options = JSON.parse(rawOptions);
return {
diffInfo,
mergedPullRequests,
options
};
}
else {
return null;
}
}
exports.checkExportedData = checkExportedData;
/** /**
* Retrieves the configuration given the file path, if not found it will fallback to the `DefaultConfiguration` * Retrieves the configuration given the file path, if not found it will fallback to the `DefaultConfiguration`
*/ */
@@ -2285,10 +2378,18 @@ function haveCommonElements(arr1, arr2) {
return arr1.some(item => arr2.has(item)); return arr1.some(item => arr2.has(item));
} }
exports.haveCommonElements = haveCommonElements; exports.haveCommonElements = haveCommonElements;
function haveCommonElementsArr(arr1, arr2) {
return haveCommonElements(arr1, new Set(arr2));
}
exports.haveCommonElementsArr = haveCommonElementsArr;
function haveEveryElements(arr1, arr2) { function haveEveryElements(arr1, arr2) {
return arr1.every(item => arr2.has(item)); return arr1.every(item => arr2.has(item));
} }
exports.haveEveryElements = haveEveryElements; exports.haveEveryElements = haveEveryElements;
function haveEveryElementsArr(arr1, arr2) {
return haveEveryElements(arr1, new Set(arr2));
}
exports.haveEveryElementsArr = haveEveryElementsArr;
/***/ }), /***/ }),
Generated Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -165,7 +165,7 @@ export class Commits {
mergeCommitSha: commit.sha, mergeCommitSha: commit.sha,
author: commit.author || '', author: commit.author || '',
repoName: '', repoName: '',
labels: new Set(), labels: [],
milestone: '', milestone: '',
body: commit.message || '', body: commit.message || '',
assignees: [], assignees: [],
+4
View File
@@ -54,6 +54,8 @@ async function run(): Promise<void> {
const fetchReleaseInformation = core.getInput('fetchReleaseInformation') === 'true' const fetchReleaseInformation = core.getInput('fetchReleaseInformation') === 'true'
const fetchReviews = core.getInput('fetchReviews') === 'true' const fetchReviews = core.getInput('fetchReviews') === 'true'
const commitMode = core.getInput('commitMode') === 'true' const commitMode = core.getInput('commitMode') === 'true'
const exportCollected = core.getInput('exportCollected') === 'true'
const exportOnly = core.getInput('exportOnly') === 'true'
const result = await new ReleaseNotesBuilder( const result = await new ReleaseNotesBuilder(
baseUrl, baseUrl,
@@ -70,6 +72,8 @@ async function run(): Promise<void> {
fetchReleaseInformation, fetchReleaseInformation,
fetchReviews, fetchReviews,
commitMode, commitMode,
exportCollected,
exportOnly,
configuration configuration
).build() ).build()
+4 -4
View File
@@ -17,7 +17,7 @@ export interface PullRequestInfo {
mergeCommitSha: string mergeCommitSha: string
author: string author: string
repoName: string repoName: string
labels: Set<string> labels: string[]
milestone: string milestone: string
body: string body: string
assignees: string[] assignees: string[]
@@ -329,8 +329,8 @@ export function retrieveProperty(pr: PullRequestInfo, property: Property, useCas
} }
// helper function to add a special open label to prs not merged. // helper function to add a special open label to prs not merged.
function attachSpeciaLabels(status: 'open' | 'merged', labels: Set<string>): Set<string> { function attachSpeciaLabels(status: 'open' | 'merged', labels: string[]): string[] {
labels.add(`--rcba-${status}`) labels.push(`--rcba-${status}`)
return labels return labels
} }
@@ -345,7 +345,7 @@ const mapPullRequest = (pr: PullData | Unpacked<PullsListData>, status: 'open' |
mergeCommitSha: pr.merge_commit_sha || '', mergeCommitSha: pr.merge_commit_sha || '',
author: pr.user?.login || '', author: pr.user?.login || '',
repoName: pr.base.repo.full_name, repoName: pr.base.repo.full_name,
labels: attachSpeciaLabels(status, new Set(pr.labels?.map(lbl => lbl.name?.toLocaleLowerCase('en') || '') || [])), labels: attachSpeciaLabels(status, pr.labels?.map(lbl => lbl.name?.toLocaleLowerCase('en') || '') || []),
milestone: pr.milestone?.title || '', milestone: pr.milestone?.title || '',
body: pr.body || '', body: pr.body || '',
assignees: pr.assignees?.map(asignee => asignee?.login || '') || [], assignees: pr.assignees?.map(asignee => asignee?.login || '') || [],
+70 -9
View File
@@ -2,11 +2,13 @@ import * as core from '@actions/core'
import {Configuration} from './configuration' import {Configuration} from './configuration'
import {Octokit} from '@octokit/rest' import {Octokit} from '@octokit/rest'
import {TagInfo, Tags} from './tags' import {TagInfo, Tags} from './tags'
import {failOrError} from './utils' import {checkExportedData, failOrError} from './utils'
import {HttpsProxyAgent} from 'https-proxy-agent' import {HttpsProxyAgent} from 'https-proxy-agent'
import {PullRequestInfo, PullRequests} from './pullRequests' import {PullRequestInfo, PullRequests} from './pullRequests'
import {Commits, DiffInfo} from './commits' import {Commits, DiffInfo} from './commits'
import {buildChangelog} from './transform' import {buildChangelog} from './transform'
import * as fs from 'fs'
import path from 'path'
export interface ReleaseNotesOptions { export interface ReleaseNotesOptions {
owner: string // the owner of the repository owner: string // the owner of the repository
@@ -43,11 +45,15 @@ export class ReleaseNotesBuilder {
private fetchReviewers: boolean = false, private fetchReviewers: boolean = false,
private fetchReleaseInformation: boolean = false, private fetchReleaseInformation: boolean = false,
private fetchReviews: boolean = false, private fetchReviews: boolean = false,
private commitMode: boolean, private commitMode: boolean = false,
private exportCollected: boolean = false,
private exportOnly: boolean = false,
private configuration: Configuration private configuration: Configuration
) {} ) {}
async build(): Promise<string | null> { async build(): Promise<string | null> {
let releaseNotesData = checkExportedData()
if (releaseNotesData == null) {
if (!this.owner) { if (!this.owner) {
failOrError(`💥 Missing or couldn't resolve 'owner'`, this.failOnError) failOrError(`💥 Missing or couldn't resolve 'owner'`, this.failOnError)
return null return null
@@ -145,12 +151,60 @@ export class ReleaseNotesBuilder {
configuration: this.configuration configuration: this.configuration
} }
const releaseNotesData = await pullData(octokit, options) releaseNotesData = await pullData(octokit, options, this.exportCollected, this.exportOnly)
} else {
core.info(`️ Retrieved previously exported collected data`)
// merge input with options (in case some data was updated)
const diffInfo = releaseNotesData.diffInfo
const mergedPullRequests = releaseNotesData.mergedPullRequests
const orgOptions = releaseNotesData.options
// merge fromTag info with provided info || otherwise use cached info
const fromTag: TagInfo = orgOptions.fromTag
if (this.fromTag != null) {
fromTag.name = this.fromTag
}
const toTag: TagInfo = orgOptions.toTag
if (this.toTag != null) {
toTag.name = this.toTag
}
// merge provided values with previous options (prefer provided)
const options: ReleaseNotesOptions = {
owner: this.owner || orgOptions.owner,
repo: this.repo || orgOptions.repo,
fromTag,
toTag,
includeOpen: this.includeOpen || orgOptions.includeOpen,
failOnError: this.failOnError || orgOptions.failOnError,
fetchReviewers: this.fetchReviewers || orgOptions.fetchReviewers,
fetchReleaseInformation: this.fetchReleaseInformation || orgOptions.fetchReleaseInformation,
fetchReviews: this.fetchReviews || orgOptions.fetchReviews,
commitMode: this.commitMode || orgOptions.commitMode,
configuration: this.configuration || orgOptions.configuration
}
releaseNotesData = {
diffInfo,
mergedPullRequests,
options
}
}
if (releaseNotesData != null) {
return buildChangelog(releaseNotesData.diffInfo, releaseNotesData.mergedPullRequests, releaseNotesData.options) return buildChangelog(releaseNotesData.diffInfo, releaseNotesData.mergedPullRequests, releaseNotesData.options)
} else {
return null
}
} }
} }
export async function pullData(octokit: Octokit, options: ReleaseNotesOptions): Promise<ReleaseNotesData> { export async function pullData(
octokit: Octokit,
options: ReleaseNotesOptions,
exportCollected: boolean,
exportOnly: boolean
): Promise<ReleaseNotesData | null> {
let mergedPullRequests: PullRequestInfo[] let mergedPullRequests: PullRequestInfo[]
let diffInfo: DiffInfo let diffInfo: DiffInfo
@@ -184,12 +238,19 @@ export async function pullData(octokit: Octokit, options: ReleaseNotesOptions):
core.setOutput('changes', diffInfo.changes) core.setOutput('changes', diffInfo.changes)
core.setOutput('commits', diffInfo.commits) core.setOutput('commits', diffInfo.commits)
const collectAndExport = true if (exportCollected) {
if (collectAndExport) {
core.info('📦 Exporting collected data') core.info('📦 Exporting collected data')
core.exportVariable('_diffInfo', JSON.stringify(diffInfo)) core.exportVariable(`RCBA_EXPORT_diffInfo`, JSON.stringify(diffInfo))
core.exportVariable('_mergedPullRequests', JSON.stringify(mergedPullRequests)) //fs.writeFileSync(path.resolve('diffInfo.json'), JSON.stringify(diffInfo))
core.exportVariable('_options', JSON.stringify(options)) core.exportVariable(`RCBA_EXPORT_mergedPullRequests`, JSON.stringify(mergedPullRequests))
//fs.writeFileSync(path.resolve('mergedPullRequests.json'), JSON.stringify(mergedPullRequests))
core.exportVariable(`RCBA_EXPORT_options`, JSON.stringify(options))
//fs.writeFileSync(path.resolve('options.json'), JSON.stringify(options))
if (exportOnly) {
core.endGroup()
return null
}
} }
core.endGroup() core.endGroup()
+6 -6
View File
@@ -3,7 +3,7 @@ import {Category, Configuration, Placeholder, Property, Transformer} from './con
import {CommentInfo, EMPTY_COMMENT_INFO, PullRequestInfo, retrieveProperty, sortPullRequests} from './pullRequests' import {CommentInfo, EMPTY_COMMENT_INFO, PullRequestInfo, retrieveProperty, sortPullRequests} from './pullRequests'
import {ReleaseNotesOptions} from './releaseNotesBuilder' import {ReleaseNotesOptions} from './releaseNotesBuilder'
import {DiffInfo} from './commits' import {DiffInfo} from './commits'
import {createOrSet, haveCommonElements, haveEveryElements} from './utils' import {createOrSet, haveCommonElementsArr, haveEveryElementsArr} from './utils'
import {matchesRules, RegexTransformer, validateTransformer} from './regexUtils' import {matchesRules, RegexTransformer, validateTransformer} from './regexUtils'
const EMPTY_MAP = new Map<string, string>() const EMPTY_MAP = new Map<string, string>()
@@ -57,7 +57,7 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
const extracted = extractValues(pr, extractor, 'label_extractor') const extracted = extractValues(pr, extractor, 'label_extractor')
if (extracted !== null) { if (extracted !== null) {
for (const label of extracted) { for (const label of extracted) {
pr.labels.add(label) pr.labels.push(label)
} }
if (core.isDebug()) { if (core.isDebug()) {
@@ -100,7 +100,7 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
// bring elements in order // bring elements in order
for (const [pr, body] of transformedMap) { for (const [pr, body] of transformedMap) {
if ( if (
haveCommonElements( haveCommonElementsArr(
ignoredLabels.map(lbl => lbl.toLocaleLowerCase('en')), ignoredLabels.map(lbl => lbl.toLocaleLowerCase('en')),
pr.labels pr.labels
) )
@@ -119,7 +119,7 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
// check if any exclude label matches // check if any exclude label matches
if (category.exclude_labels !== undefined) { if (category.exclude_labels !== undefined) {
if ( if (
haveCommonElements( haveCommonElementsArr(
category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')), category.exclude_labels.map(lbl => lbl.toLocaleLowerCase('en')),
pr.labels pr.labels
) )
@@ -136,7 +136,7 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
// validate for an exhaustive match (e.g. every provided rule applies) // validate for an exhaustive match (e.g. every provided rule applies)
if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) { if (category.exhaustive === true && (category.labels !== undefined || category.rules !== undefined)) {
if (category.labels !== undefined) { if (category.labels !== undefined) {
matched = haveEveryElements( matched = haveEveryElementsArr(
category.labels.map(lbl => lbl.toLocaleLowerCase('en')), category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
pr.labels pr.labels
) )
@@ -152,7 +152,7 @@ export function buildChangelog(diffInfo: DiffInfo, prs: PullRequestInfo[], optio
// if not exhaustive, do individual matches // if not exhaustive, do individual matches
if (category.labels !== undefined) { if (category.labels !== undefined) {
// check if either any of the labels applies // check if either any of the labels applies
matched = haveCommonElements( matched = haveCommonElementsArr(
category.labels.map(lbl => lbl.toLocaleLowerCase('en')), category.labels.map(lbl => lbl.toLocaleLowerCase('en')),
pr.labels pr.labels
) )
+51
View File
@@ -2,6 +2,10 @@ import * as core from '@actions/core'
import * as fs from 'fs' import * as fs from 'fs'
import * as path from 'path' import * as path from 'path'
import {Configuration, DefaultConfiguration} from './configuration' import {Configuration, DefaultConfiguration} from './configuration'
import {ReleaseNotesData, ReleaseNotesOptions} from './releaseNotesBuilder'
import {DiffInfo} from './commits'
import {PullRequestInfo} from './pullRequests'
import moment from 'moment'
/** /**
* Resolves the repository path, relatively to the GITHUB_WORKSPACE * Resolves the repository path, relatively to the GITHUB_WORKSPACE
*/ */
@@ -32,6 +36,45 @@ export function failOrError(message: string | Error, failOnError: boolean): void
} }
} }
/**
* Retrieves the exported information from a previous run of the `release-changelog-builder-action`.
* If available, return a [ReleaseNotesData].
*/
export function checkExportedData(): ReleaseNotesData | null {
const rawDiffInfo = process.env[`RCBA_EXPORT_diffInfo`]
const rawMergedPullRequests = process.env[`RCBA_EXPORT_mergedPullRequests`]
const rawOptions = process.env[`RCBA_EXPORT_options`]
if (rawDiffInfo && rawMergedPullRequests && rawOptions) {
const diffInfo: DiffInfo = JSON.parse(rawDiffInfo)
const mergedPullRequests: PullRequestInfo[] = JSON.parse(rawMergedPullRequests)
for (const pr of mergedPullRequests) {
pr.createdAt = moment(pr.createdAt)
if (pr.mergedAt) {
pr.mergedAt = moment(pr.mergedAt)
}
if (pr.reviews) {
for (const review of pr.reviews) {
if (review.submittedAt) {
review.submittedAt = moment(review.submittedAt)
}
}
}
}
const options: ReleaseNotesOptions = JSON.parse(rawOptions)
return {
diffInfo,
mergedPullRequests,
options
}
} else {
return null
}
}
/** /**
* Retrieves the configuration given the file path, if not found it will fallback to the `DefaultConfiguration` * Retrieves the configuration given the file path, if not found it will fallback to the `DefaultConfiguration`
*/ */
@@ -172,6 +215,14 @@ export function haveCommonElements(arr1: string[], arr2: Set<string>): boolean {
return arr1.some(item => arr2.has(item)) return arr1.some(item => arr2.has(item))
} }
export function haveCommonElementsArr(arr1: string[], arr2: string[]): boolean {
return haveCommonElements(arr1, new Set(arr2))
}
export function haveEveryElements(arr1: string[], arr2: Set<string>): boolean { export function haveEveryElements(arr1: string[], arr2: Set<string>): boolean {
return arr1.every(item => arr2.has(item)) return arr1.every(item => arr2.has(item))
} }
export function haveEveryElementsArr(arr1: string[], arr2: string[]): boolean {
return haveEveryElements(arr1, new Set(arr2))
}