mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 00:20:04 +01:00
159 lines
4.6 KiB
JavaScript
159 lines
4.6 KiB
JavaScript
'use strict';
|
|
|
|
const {stablePackages} = require('../../../ReactVersions');
|
|
const {parseArgs} = require('./args');
|
|
const {
|
|
fetchNpmInfo,
|
|
collectCommitsSince,
|
|
loadCommitDetails,
|
|
extractPrNumber,
|
|
fetchPullRequestMetadata,
|
|
} = require('./data');
|
|
const {summarizePackages} = require('./summaries');
|
|
const {buildChangelogEntries, renderChangelog} = require('./formatters');
|
|
const {noopLogger} = require('./utils');
|
|
|
|
async function main() {
|
|
const {packageSpecs, summarizer, debug, format} = parseArgs(
|
|
process.argv.slice(2)
|
|
);
|
|
const log = debug
|
|
? (...args) => console.log('[generate-changelog]', ...args)
|
|
: noopLogger;
|
|
|
|
const allStablePackages = Object.keys(stablePackages);
|
|
const packageTargets = new Map();
|
|
for (let i = 0; i < packageSpecs.length; i++) {
|
|
const spec = packageSpecs[i];
|
|
if (!allStablePackages.includes(spec.name)) {
|
|
throw new Error(
|
|
`Package "${spec.name}" is not listed in stablePackages.`
|
|
);
|
|
}
|
|
if (packageTargets.has(spec.name)) {
|
|
throw new Error(`Package "${spec.name}" was specified more than once.`);
|
|
}
|
|
packageTargets.set(spec.name, spec);
|
|
}
|
|
|
|
const targetPackages = packageSpecs.map(spec => spec.name);
|
|
log(
|
|
`Starting changelog generation for: ${packageSpecs
|
|
.map(spec => `${spec.name}@${spec.displayVersion || spec.version}`)
|
|
.join(', ')}`
|
|
);
|
|
|
|
const packageInfoMap = new Map();
|
|
const packageInfoResults = await Promise.all(
|
|
targetPackages.map(async pkg => {
|
|
const info = await fetchNpmInfo(pkg, {log});
|
|
return {pkg, info};
|
|
})
|
|
);
|
|
for (let i = 0; i < packageInfoResults.length; i++) {
|
|
const entry = packageInfoResults[i];
|
|
packageInfoMap.set(entry.pkg, entry.info);
|
|
}
|
|
|
|
const commitPackagesMap = new Map();
|
|
const commitCollections = await Promise.all(
|
|
targetPackages.map(async pkg => {
|
|
const {gitHead} = packageInfoMap.get(pkg);
|
|
const commits = await collectCommitsSince(pkg, gitHead, {log});
|
|
log(`Package ${pkg} has ${commits.length} commit(s) since ${gitHead}.`);
|
|
return {pkg, commits};
|
|
})
|
|
);
|
|
for (let i = 0; i < commitCollections.length; i++) {
|
|
const entry = commitCollections[i];
|
|
const pkg = entry.pkg;
|
|
const commits = entry.commits;
|
|
for (let j = 0; j < commits.length; j++) {
|
|
const sha = commits[j];
|
|
if (!commitPackagesMap.has(sha)) {
|
|
commitPackagesMap.set(sha, new Set());
|
|
}
|
|
commitPackagesMap.get(sha).add(pkg);
|
|
}
|
|
}
|
|
log(`Found ${commitPackagesMap.size} commits touching target packages.`);
|
|
|
|
if (commitPackagesMap.size === 0) {
|
|
console.log('No commits found for the selected packages.');
|
|
return;
|
|
}
|
|
|
|
const commitDetails = await Promise.all(
|
|
Array.from(commitPackagesMap.entries()).map(
|
|
async ([sha, packagesTouched]) => {
|
|
const detail = await loadCommitDetails(sha, {log});
|
|
detail.packages = packagesTouched;
|
|
detail.prNumber = extractPrNumber(detail.subject, detail.body);
|
|
return detail;
|
|
}
|
|
)
|
|
);
|
|
|
|
commitDetails.sort((a, b) => a.timestamp - b.timestamp);
|
|
log(`Ordered ${commitDetails.length} commit(s) chronologically.`);
|
|
|
|
const commitsByPackage = new Map();
|
|
commitDetails.forEach(commit => {
|
|
commit.packages.forEach(pkgName => {
|
|
if (!commitsByPackage.has(pkgName)) {
|
|
commitsByPackage.set(pkgName, []);
|
|
}
|
|
commitsByPackage.get(pkgName).push(commit);
|
|
});
|
|
});
|
|
|
|
const uniquePrNumbers = Array.from(
|
|
new Set(commitDetails.map(commit => commit.prNumber).filter(Boolean))
|
|
);
|
|
log(`Identified ${uniquePrNumbers.length} unique PR number(s).`);
|
|
|
|
const prMetadata = new Map();
|
|
log(`Summarizer selected: ${summarizer || 'none (using commit titles)'}`);
|
|
const prMetadataResults = await Promise.all(
|
|
uniquePrNumbers.map(async prNumber => {
|
|
const meta = await fetchPullRequestMetadata(prNumber, {log});
|
|
return {prNumber, meta};
|
|
})
|
|
);
|
|
for (let i = 0; i < prMetadataResults.length; i++) {
|
|
const entry = prMetadataResults[i];
|
|
if (entry.meta) {
|
|
prMetadata.set(entry.prNumber, entry.meta);
|
|
}
|
|
}
|
|
log(`Fetched metadata for ${prMetadata.size} PR(s).`);
|
|
|
|
const summariesByPackage = await summarizePackages({
|
|
summarizer,
|
|
packageSpecs,
|
|
packageTargets,
|
|
commitsByPackage,
|
|
log,
|
|
});
|
|
|
|
const changelogEntries = buildChangelogEntries({
|
|
packageSpecs,
|
|
commitsByPackage,
|
|
summariesByPackage,
|
|
prMetadata,
|
|
});
|
|
|
|
log('Generated changelog sections.');
|
|
const output = renderChangelog(changelogEntries, format);
|
|
console.log(output);
|
|
}
|
|
|
|
if (require.main === module) {
|
|
main().catch(error => {
|
|
process.stderr.write(`${error.message}\n`);
|
|
process.exit(1);
|
|
});
|
|
} else {
|
|
module.exports = main;
|
|
}
|