@roadiehq/backstage-plugin-github-pull-requests
Version:
150 lines (147 loc) • 4.73 kB
JavaScript
import { useAsync } from 'react-use';
import { githubPullRequestsApiRef } from '../api/GithubPullRequestsApi.esm.js';
import '@backstage/integration';
import '@octokit/rest';
import { Duration } from 'luxon';
import { useApi } from '@backstage/core-plugin-api';
import { useEntity } from '@backstage/plugin-catalog-react';
import { getHostname } from '../utils/githubUtils.esm.js';
function calculateStatistics(pullRequestsData) {
const result = pullRequestsData.reduce(
(acc, curr) => {
acc.avgTimeUntilMerge += curr.pullRequest.mergedAt ? new Date(curr.pullRequest.mergedAt).getTime() - new Date(curr.createdAt).getTime() : 0;
const avgCodingTime = new Date(curr.createdAt).getTime() - new Date(curr.firstCommitAt).getTime();
acc.avgCodingTime += avgCodingTime > 0 ? avgCodingTime : 0;
acc.mergedCount += curr.pullRequest.mergedAt ? 1 : 0;
acc.closedCount += curr.closedAt ? 1 : 0;
acc.additions += curr.pullRequest.additions;
acc.deletions += curr.pullRequest.deletions;
acc.changedLinesCount += curr.pullRequest.additions + curr.pullRequest.deletions;
acc.changedFilesCount += curr.pullRequest.changedFiles;
return acc;
},
{
avgTimeUntilMerge: 0,
avgCodingTime: 0,
closedCount: 0,
mergedCount: 0,
changedLinesCount: 0,
changedFilesCount: 0,
additions: 0,
deletions: 0
}
);
return {
...result,
avgChangedLinesCount: Math.round(
result.changedLinesCount / pullRequestsData.length
),
avgChangedFilesCount: Math.round(
result.changedFilesCount / pullRequestsData.length
),
avgAdditions: Math.round(result.additions / pullRequestsData.length),
avgDeletions: Math.round(result.deletions / pullRequestsData.length)
};
}
function usePullRequestsStatistics({
owner,
repo,
branch,
pageSize,
state
}) {
const api = useApi(githubPullRequestsApiRef);
const { entity } = useEntity();
const hostname = getHostname(entity);
const {
loading,
value: statsData,
error
} = useAsync(async () => {
if (!repo) {
return {
avgTimeUntilMerge: "Never",
avgCodingTime: "Never",
mergedToClosedRatio: "0%",
avgChangedLinesCount: 0,
avgChangedFilesCount: 0,
avgAdditions: 0,
avgDeletions: 0
};
}
const {
pullRequestsData
} = await api.listPullRequests({
search: `state:${state}`,
hostname,
owner,
repo,
pageSize,
page: 1,
branch
});
const botUsernames = [
"github-actions[bot]",
"dependabot[bot]",
"roadie-bot"
];
const transformedData = await Promise.all(
pullRequestsData.items.filter((obj) => {
const login = obj.user?.login;
return login && !botUsernames.includes(login);
}).map(async (pr) => {
const repoData = await api.getRepositoryData({
url: pr.pull_request.url,
hostname
});
const commitDate = await api.getCommitDetailsData({
hostname,
owner,
repo,
number: pr.number
});
return {
createdAt: pr.created_at,
closedAt: pr.closed_at,
firstCommitAt: commitDate.firstCommitDate.toString(),
pullRequest: {
mergedAt: pr.pull_request.merged_at,
additions: repoData.additions,
deletions: repoData.deletions,
changedFiles: repoData.changedFiles
}
};
})
);
const calcResult = calculateStatistics(transformedData);
if (calcResult.closedCount === 0 || calcResult.mergedCount === 0)
return {
...calcResult,
avgTimeUntilMerge: "Never",
avgCodingTime: "Never",
mergedToClosedRatio: "0%"
};
const avgTimeUntilMergeDiff = calcResult.avgTimeUntilMerge / calcResult.mergedCount;
const avgTimeUntilMerge = Duration.fromMillis(avgTimeUntilMergeDiff).shiftTo("months", "days", "hour").toHuman({ notation: "compact" });
const avgCodingTimeUntilPRRaised = calcResult.avgCodingTime / transformedData.length;
const avgCodingTime = Duration.fromMillis(avgCodingTimeUntilPRRaised).shiftTo("months", "days", "hour").toHuman({ notation: "compact" });
return {
...calcResult,
avgTimeUntilMerge,
avgCodingTime,
mergedToClosedRatio: `${Math.round(
calcResult.mergedCount / calcResult.closedCount * 100
)}%`
};
}, [pageSize, repo, owner]);
return [
{
loading,
statsData,
projectName: `${owner}/${repo}`,
error
}
];
}
export { usePullRequestsStatistics };
//# sourceMappingURL=usePullRequestsStatistics.esm.js.map