mirror of
https://github.com/zebrajr/react.git
synced 2025-12-07 12:20:38 +01:00
191 lines
4.9 KiB
JavaScript
191 lines
4.9 KiB
JavaScript
'use strict';
|
|
|
|
const https = require('https');
|
|
const path = require('path');
|
|
|
|
const {execFileAsync, repoRoot} = require('./utils');
|
|
|
|
async function fetchNpmInfo(packageName, {log}) {
|
|
const npmArgs = ['view', `${packageName}@latest`, '--json'];
|
|
const options = {cwd: repoRoot, maxBuffer: 10 * 1024 * 1024};
|
|
log(`Fetching npm info for ${packageName}...`);
|
|
const {stdout} = await execFileAsync('npm', npmArgs, options);
|
|
|
|
let data = stdout.trim();
|
|
if (!data) {
|
|
throw new Error(`npm view returned empty result for ${packageName}`);
|
|
}
|
|
|
|
let info = JSON.parse(data);
|
|
if (Array.isArray(info)) {
|
|
info = info[info.length - 1];
|
|
}
|
|
|
|
const version = info.version || info['dist-tags']?.latest;
|
|
let gitHead = info.gitHead || null;
|
|
|
|
if (!gitHead) {
|
|
const gitHeadResult = await execFileAsync(
|
|
'npm',
|
|
['view', `${packageName}@${version}`, 'gitHead'],
|
|
{cwd: repoRoot, maxBuffer: 1024 * 1024}
|
|
);
|
|
const possibleGitHead = gitHeadResult.stdout.trim();
|
|
if (
|
|
possibleGitHead &&
|
|
possibleGitHead !== 'undefined' &&
|
|
possibleGitHead !== 'null'
|
|
) {
|
|
log(`Found gitHead for ${packageName}@${version}: ${possibleGitHead}`);
|
|
gitHead = possibleGitHead;
|
|
}
|
|
}
|
|
|
|
if (!version) {
|
|
throw new Error(
|
|
`Unable to determine latest published version for ${packageName}`
|
|
);
|
|
}
|
|
if (!gitHead) {
|
|
throw new Error(
|
|
`Unable to determine git commit for ${packageName}@${version}`
|
|
);
|
|
}
|
|
|
|
return {
|
|
publishedVersion: version,
|
|
gitHead,
|
|
};
|
|
}
|
|
|
|
async function collectCommitsSince(packageName, sinceGitSha, {log}) {
|
|
log(`Collecting commits for ${packageName} since ${sinceGitSha}...`);
|
|
await execFileAsync('git', ['cat-file', '-e', `${sinceGitSha}^{commit}`], {
|
|
cwd: repoRoot,
|
|
});
|
|
const {stdout} = await execFileAsync(
|
|
'git',
|
|
[
|
|
'rev-list',
|
|
'--reverse',
|
|
`${sinceGitSha}..HEAD`,
|
|
'--',
|
|
path.posix.join('packages', packageName),
|
|
],
|
|
{cwd: repoRoot, maxBuffer: 10 * 1024 * 1024}
|
|
);
|
|
|
|
return stdout
|
|
.trim()
|
|
.split('\n')
|
|
.map(line => line.trim())
|
|
.filter(Boolean);
|
|
}
|
|
|
|
async function loadCommitDetails(sha, {log}) {
|
|
log(`Loading commit details for ${sha}...`);
|
|
const format = ['%H', '%s', '%an', '%ae', '%ct', '%B'].join('%n');
|
|
const {stdout} = await execFileAsync(
|
|
'git',
|
|
['show', '--quiet', `--format=${format}`, sha],
|
|
{cwd: repoRoot, maxBuffer: 10 * 1024 * 1024}
|
|
);
|
|
|
|
const [commitSha, subject, authorName, authorEmail, timestamp, ...rest] =
|
|
stdout.split('\n');
|
|
const body = rest.join('\n').trim();
|
|
|
|
return {
|
|
sha: commitSha.trim(),
|
|
subject: subject.trim(),
|
|
authorName: authorName.trim(),
|
|
authorEmail: authorEmail.trim(),
|
|
timestamp: +timestamp.trim() || 0,
|
|
body,
|
|
};
|
|
}
|
|
|
|
function extractPrNumber(subject, body) {
|
|
const patterns = [
|
|
/\(#(\d+)\)/,
|
|
/https:\/\/github\.com\/facebook\/react\/pull\/(\d+)/,
|
|
];
|
|
|
|
for (let i = 0; i < patterns.length; i++) {
|
|
const pattern = patterns[i];
|
|
const subjectMatch = subject && subject.match(pattern);
|
|
if (subjectMatch) {
|
|
return subjectMatch[1];
|
|
}
|
|
const bodyMatch = body && body.match(pattern);
|
|
if (bodyMatch) {
|
|
return bodyMatch[1];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
async function fetchPullRequestMetadata(prNumber, {log}) {
|
|
log(`Fetching PR metadata for #${prNumber}...`);
|
|
const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN || null;
|
|
const requestOptions = {
|
|
hostname: 'api.github.com',
|
|
path: `/repos/facebook/react/pulls/${prNumber}`,
|
|
method: 'GET',
|
|
headers: {
|
|
'User-Agent': 'generate-changelog-script',
|
|
Accept: 'application/vnd.github+json',
|
|
},
|
|
};
|
|
if (token) {
|
|
requestOptions.headers.Authorization = `Bearer ${token}`;
|
|
}
|
|
|
|
return new Promise(resolve => {
|
|
const req = https.request(requestOptions, res => {
|
|
let raw = '';
|
|
res.on('data', chunk => {
|
|
raw += chunk;
|
|
});
|
|
res.on('end', () => {
|
|
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
try {
|
|
const json = JSON.parse(raw);
|
|
resolve({
|
|
authorLogin: json.user?.login || null,
|
|
});
|
|
} catch (error) {
|
|
process.stderr.write(
|
|
`Warning: unable to parse GitHub response for PR #${prNumber}: ${error.message}\n`
|
|
);
|
|
resolve(null);
|
|
}
|
|
} else {
|
|
process.stderr.write(
|
|
`Warning: GitHub API request failed for PR #${prNumber} with status ${res.statusCode}\n`
|
|
);
|
|
resolve(null);
|
|
}
|
|
});
|
|
});
|
|
|
|
req.on('error', error => {
|
|
process.stderr.write(
|
|
`Warning: GitHub API request errored for PR #${prNumber}: ${error.message}\n`
|
|
);
|
|
resolve(null);
|
|
});
|
|
|
|
req.end();
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
fetchNpmInfo,
|
|
collectCommitsSince,
|
|
loadCommitDetails,
|
|
extractPrNumber,
|
|
fetchPullRequestMetadata,
|
|
};
|