mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 01:18:42 +00:00
Automation: Report on CEO PR open time (#13674)
. --------- Co-authored-by: Mike McNeil <mikermcneil@users.noreply.github.com>
This commit is contained in:
parent
fe97a59447
commit
09be914450
1 changed files with 87 additions and 14 deletions
101
website/scripts/get-bug-and-pr-report.js
vendored
101
website/scripts/get-bug-and-pr-report.js
vendored
|
|
@ -4,7 +4,7 @@ module.exports = {
|
|||
friendlyName: 'Get bug and PR report',
|
||||
|
||||
|
||||
description: 'Get information about open bugs and closed pull requests in the fleetdm/fleet GitHub repo.',
|
||||
description: 'Get information about open bugs and pull requests.',
|
||||
|
||||
|
||||
inputs: {
|
||||
|
|
@ -14,8 +14,6 @@ module.exports = {
|
|||
|
||||
fn: async function ({}) {
|
||||
|
||||
sails.log('Getting metrics for issues with the "bug" label and pull requests in the fleetdm/fleet Github repo...');
|
||||
|
||||
if(!sails.config.custom.githubAccessToken) {
|
||||
throw new Error('Missing GitHub access token! To use this script, a GitHub access token is required. To resolve, add a GitHub access token to your local configuration (website/config/local.js) as sails.config.custom.githubAccessToken or provide one when running this script. (ex: "sails_custom__githubAccessToken=YOUR_PERSONAL_ACCESS_TOKEN sails run get-bug-and-pr-report")');
|
||||
}
|
||||
|
|
@ -35,6 +33,11 @@ module.exports = {
|
|||
let daysSinceContributorPullRequestsWereOpened = [];
|
||||
let commitToMergeTimesInDays = [];
|
||||
|
||||
let allPublicOpenPrs = [];
|
||||
let publicPrsMergedInThePastThreeWeeks = [];
|
||||
let allNonPublicOpenPrs = [];
|
||||
let nonPublicPrsClosedInThePastThreeWeeks = [];
|
||||
|
||||
|
||||
await sails.helpers.flow.simultaneously([
|
||||
|
||||
|
|
@ -93,10 +96,9 @@ module.exports = {
|
|||
async()=>{
|
||||
|
||||
let pageNumberForPaginatedResults = 0;
|
||||
let pullRequestsMergedInThePastThreeWeeks = [];
|
||||
|
||||
|
||||
// Fetch the last 300 closed pull requests from the fleetdm/fleet GitHub Repo
|
||||
// [?] https://docs.github.com/en/free-pro-team@latest/rest/pulls/pulls#list-pull-requests
|
||||
await sails.helpers.flow.until(async ()=>{
|
||||
// Increment the page of results we're requesting.
|
||||
pageNumberForPaginatedResults += 1;
|
||||
|
|
@ -118,18 +120,21 @@ module.exports = {
|
|||
});
|
||||
|
||||
// Add the filtered array of PRs to the array of all pull requests merged in the past three weeks.
|
||||
pullRequestsMergedInThePastThreeWeeks = pullRequestsMergedInThePastThreeWeeks.concat(resultsToAdd);
|
||||
publicPrsMergedInThePastThreeWeeks = publicPrsMergedInThePastThreeWeeks.concat(resultsToAdd);
|
||||
// Stop when we've received results from the third page.
|
||||
return pageNumberForPaginatedResults === 3;
|
||||
});
|
||||
|
||||
|
||||
// To get the timestamp of the first commit for each pull request, we'll need to send a request to the commits API endpoint.
|
||||
await sails.helpers.flow.simultaneouslyForEach(pullRequestsMergedInThePastThreeWeeks, async (pullRequest)=>{
|
||||
await sails.helpers.flow.simultaneouslyForEach(publicPrsMergedInThePastThreeWeeks, async (pullRequest)=>{
|
||||
// Create a date object from the PR's merged_at timestamp.
|
||||
let pullRequestMergedOn = new Date(pullRequest.merged_at);
|
||||
// https://docs.github.com/en/rest/commits/commits#list-commits
|
||||
|
||||
// Get commits on this PR.
|
||||
// [?] https://docs.github.com/en/rest/commits/commits#list-commits
|
||||
let commitsOnThisPullRequest = await sails.helpers.http.get(pullRequest.commits_url, {}, baseHeaders).retry();
|
||||
|
||||
// Create a new Date from the timestamp of the first commit on this pull request.
|
||||
let firstCommitAt = new Date(commitsOnThisPullRequest[0].commit.author.date); // https://docs.github.com/en/rest/commits/commits#list-commits--code-samples
|
||||
// Get the amount of time this issue has been open in milliseconds.
|
||||
|
|
@ -149,10 +154,10 @@ module.exports = {
|
|||
//
|
||||
async()=>{
|
||||
let pullRequestResultsPageNumber = 0;
|
||||
let allOpenPullRequests = [];
|
||||
let contributorPullRequests = [];
|
||||
// Fetch all open pull requests in the fleetdm/fleet repo.
|
||||
// Note: This will send requests to GitHub until the number of results is less than the number we requested.
|
||||
// [?] https://docs.github.com/en/free-pro-team@latest/rest/pulls/pulls#list-pull-requests
|
||||
await sails.helpers.flow.until(async ()=>{
|
||||
// Increment the page of results we're requesting.
|
||||
pullRequestResultsPageNumber += 1;
|
||||
|
|
@ -166,12 +171,12 @@ module.exports = {
|
|||
baseHeaders
|
||||
).retry();
|
||||
// Add the results to the array of results.
|
||||
allOpenPullRequests = allOpenPullRequests.concat(pullRequests);
|
||||
allPublicOpenPrs = allPublicOpenPrs.concat(pullRequests);
|
||||
// If we received less results than we requested, we've reached the last page of the results.
|
||||
return pullRequests.length !== NUMBER_OF_RESULTS_REQUESTED;
|
||||
}, 10000);
|
||||
|
||||
for(let pullRequest of allOpenPullRequests) {
|
||||
for(let pullRequest of allPublicOpenPrs) {
|
||||
// Create a date object from the PR's created_at timestamp.
|
||||
let pullRequestOpenedOn = new Date(pullRequest.created_at);
|
||||
// Get the amount of time this issue has been open in milliseconds.
|
||||
|
|
@ -189,6 +194,43 @@ module.exports = {
|
|||
}
|
||||
}//∞
|
||||
|
||||
},
|
||||
|
||||
// ███╗ ██╗ ██████╗ ███╗ ██╗ ██████╗ ██╗ ██╗██████╗ ██╗ ██╗ ██████╗
|
||||
// ████╗ ██║██╔═══██╗████╗ ██║ ██╔══██╗██║ ██║██╔══██╗██║ ██║██╔════╝
|
||||
// ██╔██╗ ██║██║ ██║██╔██╗ ██║█████╗██████╔╝██║ ██║██████╔╝██║ ██║██║
|
||||
// ██║╚██╗██║██║ ██║██║╚██╗██║╚════╝██╔═══╝ ██║ ██║██╔══██╗██║ ██║██║
|
||||
// ██║ ╚████║╚██████╔╝██║ ╚████║ ██║ ╚██████╔╝██████╔╝███████╗██║╚██████╗
|
||||
// ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═════╝
|
||||
//
|
||||
async()=>{
|
||||
|
||||
// Fetch confidential and classified PRs (current open, and recent closed)
|
||||
for (let repoName of ['classified', 'confidential']) {
|
||||
// [?] https://docs.github.com/en/free-pro-team@latest/rest/pulls/pulls#list-pull-requests
|
||||
let openPrs = await sails.helpers.http.get(`https://api.github.com/repos/fleetdm/${encodeURIComponent(repoName)}/pulls`, {
|
||||
state: 'open',
|
||||
'per_page': 100,
|
||||
page: 1,
|
||||
}, baseHeaders);
|
||||
allNonPublicOpenPrs = allNonPublicOpenPrs.concat(openPrs);
|
||||
|
||||
// [?] https://docs.github.com/en/free-pro-team@latest/rest/pulls/pulls#list-pull-requests
|
||||
let last100ClosedPrs = await sails.helpers.http.get(`https://api.github.com/repos/fleetdm/${encodeURIComponent(repoName)}/pulls`, {
|
||||
state: 'closed',
|
||||
sort: 'updated',
|
||||
direction: 'desc',
|
||||
'per_page': 100,
|
||||
page: 1,
|
||||
}, baseHeaders);
|
||||
|
||||
// Exclude draft PRs and filter the PRs we received from Github using the pull request's closed_at date.
|
||||
nonPublicPrsClosedInThePastThreeWeeks = nonPublicPrsClosedInThePastThreeWeeks.concat(
|
||||
last100ClosedPrs.filter((pr)=>{
|
||||
return !pr.draft && threeWeeksAgo.getTime() <= (new Date(pr.closed_at)).getTime();
|
||||
})
|
||||
);
|
||||
}//∞
|
||||
}
|
||||
|
||||
]);
|
||||
|
|
@ -199,17 +241,40 @@ module.exports = {
|
|||
let averageDaysPullRequestsAreOpenFor = Math.round(_.sum(daysSincePullRequestsWereOpened)/daysSincePullRequestsWereOpened.length);
|
||||
let averageDaysContributorPullRequestsAreOpenFor = Math.round(_.sum(daysSinceContributorPullRequestsWereOpened)/daysSinceContributorPullRequestsWereOpened.length);
|
||||
|
||||
|
||||
// Compute CEO-dependent PR KPIs, which are slightly simpler.
|
||||
// FUTURE: Refactor this to be less messy.
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
let ceoDependentOpenPrs = [];
|
||||
ceoDependentOpenPrs = ceoDependentOpenPrs.concat(allPublicOpenPrs.filter((pr) => !pr.draft && _.pluck(pr.labels, 'name').includes('#g-ceo')));
|
||||
ceoDependentOpenPrs = ceoDependentOpenPrs.concat(allNonPublicOpenPrs.filter((pr) => !pr.draft && _.pluck(pr.labels, 'name').includes('#g-ceo')));
|
||||
|
||||
let ceoDependentPrsMergedRecently = [];
|
||||
ceoDependentPrsMergedRecently = ceoDependentPrsMergedRecently.concat(publicPrsMergedInThePastThreeWeeks.filter((pr) => !pr.draft && _.pluck(pr.labels, 'name').includes('#g-ceo')));
|
||||
ceoDependentPrsMergedRecently = ceoDependentPrsMergedRecently.concat(nonPublicPrsClosedInThePastThreeWeeks.filter((pr) => !pr.draft && _.pluck(pr.labels, 'name').includes('#g-ceo')));
|
||||
|
||||
let ceoDependentPrOpenTime = ceoDependentPrsMergedRecently.reduce((avgDaysOpen, pr)=>{
|
||||
let openedAt = new Date(pr.created_at).getTime();
|
||||
let closedAt = new Date(pr.closed_at).getTime();
|
||||
let daysOpen = Math.abs(closedAt - openedAt) / ONE_DAY_IN_MILLISECONDS;
|
||||
avgDaysOpen = avgDaysOpen + (daysOpen / ceoDependentPrsMergedRecently.length);
|
||||
sails.log.verbose('Processing',pr.head.repo.name,':: #'+pr.number,'open '+daysOpen+' days', 'rolling avg now '+avgDaysOpen);
|
||||
return avgDaysOpen;
|
||||
}, 0);
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
|
||||
// Log the results
|
||||
sails.log(`
|
||||
Bugs:
|
||||
---------------------------
|
||||
Number of open issues with the "bug" label: ${daysSinceBugsWereOpened.length}
|
||||
Number of open issues with the "bug" label in fleetdm/fleet: ${daysSinceBugsWereOpened.length}
|
||||
Average open time: ${averageNumberOfDaysBugsAreOpenFor} days.
|
||||
|
||||
|
||||
Closed pull requests:
|
||||
---------------------------
|
||||
Number of pull requests merged in the past three weeks: ${commitToMergeTimesInDays.length}
|
||||
Number of pull requests merged in the past three weeks in fleetdm/fleet: ${commitToMergeTimesInDays.length}
|
||||
Average time from first commit to merge: ${averageNumberOfDaysFromCommitToMerge} days.
|
||||
|
||||
|
||||
|
|
@ -219,7 +284,15 @@ module.exports = {
|
|||
Average open time: ${averageDaysPullRequestsAreOpenFor} days.
|
||||
|
||||
Number of open pull requests in the fleetdm/fleet Github repo (no bots, no handbook, no ceo): ${daysSinceContributorPullRequestsWereOpened.length}
|
||||
Average open time (no bots, no handbook, no ceo): ${averageDaysContributorPullRequestsAreOpenFor} days.`);
|
||||
Average open time (no bots, no handbook, no ceo): ${averageDaysContributorPullRequestsAreOpenFor} days.
|
||||
|
||||
|
||||
Pull requests requiring CEO review
|
||||
---------------------------------------
|
||||
Number of open #g-ceo pull requests in the fleetdm Github org: ${ceoDependentOpenPrs.length}
|
||||
Average open time (#g-ceo PRs): ${Math.round(ceoDependentPrOpenTime*100)/100} days.
|
||||
`);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue