diff --git a/website/scripts/get-average-bug-and-pr-age.js b/website/scripts/get-average-bug-and-pr-age.js deleted file mode 100644 index faf741faf2..0000000000 --- a/website/scripts/get-average-bug-and-pr-age.js +++ /dev/null @@ -1,137 +0,0 @@ -module.exports = { - - - friendlyName: 'Deliver Fleet GitHub repo statistics', - - - description: 'Get the average age of open pull requests and issues with the bug label in the fleetdm/fleet GitHub repo.', - - - exits: { - - - }, - - - fn: async function () { - - sails.log('Getting average open time for issues with the "bug" label and open pull requests in the fleetdm/fleet Github repo...'); - - - let baseHeaders = { - 'User-Agent': 'Fleet average open time', - }; - - const ONE_DAY_IN_MILLISECONDS = (1000 * 60 * 60 * 24); - const todaysDate = new Date; - const NUMBER_OF_RESULTS_REQUESTED = 100; - - - // ██████╗ ██████╗ ███████╗███╗ ██╗ ██████╗ ██╗ ██╗ ██████╗ ███████╗ - // ██╔═══██╗██╔══██╗██╔════╝████╗ ██║ ██╔══██╗██║ ██║██╔════╝ ██╔════╝ - // ██║ ██║██████╔╝█████╗ ██╔██╗ ██║ ██████╔╝██║ ██║██║ ███╗███████╗ - // ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ██╔══██╗██║ ██║██║ ██║╚════██║ - // ╚██████╔╝██║ ███████╗██║ ╚████║ ██████╔╝╚██████╔╝╚██████╔╝███████║ - // ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ - // - - let pageNumberForPossiblePaginatedResults = 0; - let allIssuesWithBugLabel = []; - let daysSinceBugsWereOpened = []; - - // Fetch all open issues in the fleetdm/fleet repo with the bug label. - // Note: This will send requests to GitHub until the number of results is less than the number we requested. - await sails.helpers.flow.until(async ()=>{ - // Increment the page of results we're requesting. - pageNumberForPossiblePaginatedResults += 1; - let issuesWithBugLabel = await sails.helpers.http.get( - `https://api.github.com/repos/fleetdm/fleet/issues`, - { - 'state': 'open', - 'labels': 'bug', - 'per_page': NUMBER_OF_RESULTS_REQUESTED, - 'page': pageNumberForPossiblePaginatedResults, - }, - baseHeaders - ).retry(); - // Add the results to the allIssuesWithBugLabel array. - allIssuesWithBugLabel = allIssuesWithBugLabel.concat(issuesWithBugLabel); - // If we recieved less results than we requested, we've reached the last page of the results. - return issuesWithBugLabel.length !== NUMBER_OF_RESULTS_REQUESTED; - }, 10000); - - - for(let issue of allIssuesWithBugLabel) { - // Create a date object from the issue's created_at timestamp. - let issueOpenedOn = new Date(issue.created_at); - // Get the amount of time this issue has been open in milliseconds. - let timeOpenInMS = Math.abs(todaysDate - issueOpenedOn); - // Convert the miliseconds to days and add the value to the daysSinceBugsWereOpened array - let timeOpenInDaysRoundedDown = Math.floor(timeOpenInMS / ONE_DAY_IN_MILLISECONDS); - daysSinceBugsWereOpened.push(timeOpenInDaysRoundedDown); - } - - // Get the average open time for bugs. - let averageDaysBugsAreOpenFor = Math.floor(_.sum(daysSinceBugsWereOpened)/daysSinceBugsWereOpened.length); - - // ██████╗ ██████╗ ███████╗███╗ ██╗ ██████╗ ██████╗ ███████╗ - // ██╔═══██╗██╔══██╗██╔════╝████╗ ██║ ██╔══██╗██╔══██╗██╔════╝ - // ██║ ██║██████╔╝█████╗ ██╔██╗ ██║ ██████╔╝██████╔╝███████╗ - // ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ██╔═══╝ ██╔══██╗╚════██║ - // ╚██████╔╝██║ ███████╗██║ ╚████║ ██║ ██║ ██║███████║ - // ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ - // - - let pullRequestResultsPageNumber = 0; - let allOpenPullRequests = []; - let daysSincePullRequestsWereOpened = []; - - // 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. - await sails.helpers.flow.until(async ()=>{ - // Increment the page of results we're requesting. - pullRequestResultsPageNumber += 1; - let pullRequests = await sails.helpers.http.get( - `https://api.github.com/repos/fleetdm/fleet/pulls`, - { - 'state': 'open', - 'per_page': NUMBER_OF_RESULTS_REQUESTED, - 'page': pullRequestResultsPageNumber, - }, - baseHeaders - ).retry(); - // Add the results to the array of results. - allOpenPullRequests = allOpenPullRequests.concat(pullRequests); - // If we recieved 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) { - // 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. - let timeOpenInMS = Math.abs(todaysDate - pullRequestOpenedOn); - // Convert the miliseconds to days and add the value to the daysSincePullRequestsWereOpened array - let timeOpenInDaysRoundedDown = Math.floor(timeOpenInMS / ONE_DAY_IN_MILLISECONDS); - daysSincePullRequestsWereOpened.push(timeOpenInDaysRoundedDown); - } - - let averageDaysPullRequestsAreOpenFor = Math.floor(_.sum(daysSincePullRequestsWereOpened)/daysSincePullRequestsWereOpened.length); - - // Log the results - sails.log(`Bugs: - ------------------------------------ - Number of open issues with the "bug" label: ${daysSinceBugsWereOpened.length} - Average open time: ${averageDaysBugsAreOpenFor} days. - ------------------------------------ - - Pull requests: - ------------------------------------ - Number of open pull requests: ${daysSincePullRequestsWereOpened.length} - Average open time: ${averageDaysPullRequestsAreOpenFor} days. - ------------------------------------`); - } - - -}; - diff --git a/website/scripts/get-bug-and-pr-report.js b/website/scripts/get-bug-and-pr-report.js new file mode 100644 index 0000000000..b138516f26 --- /dev/null +++ b/website/scripts/get-bug-and-pr-report.js @@ -0,0 +1,211 @@ +module.exports = { + + + friendlyName: 'Get bug and PR report', + + + description: 'Get information about open bugs and closed pull requests in the fleetdm/fleet GitHub repo.', + + + inputs: { + + }, + + + 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")'); + } + + let baseHeaders = { + 'User-Agent': 'Fleet average open time', + 'Authorization': `token ${sails.config.custom.githubAccessToken}` + }; + + const ONE_DAY_IN_MILLISECONDS = (1000 * 60 * 60 * 24); + const todaysDate = new Date; + const threeWeeksAgo = new Date(Date.now() - (21 * ONE_DAY_IN_MILLISECONDS)); + const NUMBER_OF_RESULTS_REQUESTED = 100; + + let daysSinceBugsWereOpened = []; + let daysSincePullRequestsWereOpened = []; + let commitToMergeTimesInDays = []; + + + await sails.helpers.flow.simultaneously([ + + // ██████╗ ██████╗ ███████╗███╗ ██╗ ██████╗ ██╗ ██╗ ██████╗ ███████╗ + // ██╔═══██╗██╔══██╗██╔════╝████╗ ██║ ██╔══██╗██║ ██║██╔════╝ ██╔════╝ + // ██║ ██║██████╔╝█████╗ ██╔██╗ ██║ ██████╔╝██║ ██║██║ ███╗███████╗ + // ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ██╔══██╗██║ ██║██║ ██║╚════██║ + // ╚██████╔╝██║ ███████╗██║ ╚████║ ██████╔╝╚██████╔╝╚██████╔╝███████║ + // ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ + // + async()=>{ + + let pageNumberForPossiblePaginatedResults = 0; + let allIssuesWithBugLabel = []; + + // Fetch all open issues in the fleetdm/fleet repo with the bug label. + // Note: This will send requests to GitHub until the number of results is less than the number we requested. + await sails.helpers.flow.until(async ()=>{ + // Increment the page of results we're requesting. + pageNumberForPossiblePaginatedResults += 1; + let issuesWithBugLabel = await sails.helpers.http.get( + `https://api.github.com/repos/fleetdm/fleet/issues`, + { + 'state': 'open', + 'labels': 'bug', + 'per_page': NUMBER_OF_RESULTS_REQUESTED, + 'page': pageNumberForPossiblePaginatedResults, + }, + baseHeaders + ).retry(); + // Add the results to the allIssuesWithBugLabel array. + allIssuesWithBugLabel = allIssuesWithBugLabel.concat(issuesWithBugLabel); + // If we recieved less results than we requested, we've reached the last page of the results. + return issuesWithBugLabel.length !== NUMBER_OF_RESULTS_REQUESTED; + }, 10000); + + // iterate through the allIssuesWithBugLabel array, adding the number + for(let issue of allIssuesWithBugLabel) { + // Create a date object from the issue's created_at timestamp. + let issueOpenedOn = new Date(issue.created_at); + // Get the amount of time this issue has been open in milliseconds. + let timeOpenInMS = Math.abs(todaysDate - issueOpenedOn); + // Convert the miliseconds to days and add the value to the daysSinceBugsWereOpened array + let timeOpenInDays = timeOpenInMS / ONE_DAY_IN_MILLISECONDS; + daysSinceBugsWereOpened.push(timeOpenInDays); + } + + }, + // ██████╗██╗ ██████╗ ███████╗███████╗██████╗ ██████╗ ██████╗ ███████╗ + // ██╔════╝██║ ██╔═══██╗██╔════╝██╔════╝██╔══██╗ ██╔══██╗██╔══██╗██╔════╝ + // ██║ ██║ ██║ ██║███████╗█████╗ ██║ ██║ ██████╔╝██████╔╝███████╗ + // ██║ ██║ ██║ ██║╚════██║██╔══╝ ██║ ██║ ██╔═══╝ ██╔══██╗╚════██║ + // ╚██████╗███████╗╚██████╔╝███████║███████╗██████╔╝ ██║ ██║ ██║███████║ + // ╚═════╝╚══════╝ ╚═════╝ ╚══════╝╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ + // + async()=>{ + + let pageNumberForPaginatedResults = 0; + let pullRequestsMergedInThePastThreeWeeks = []; + + + // Fetch the last 300 closed pull requests from the fleetdm/fleet GitHub Repo + await sails.helpers.flow.until(async ()=>{ + // Increment the page of results we're requesting. + pageNumberForPaginatedResults += 1; + let closedPullRequests = await sails.helpers.http.get( + `https://api.github.com/repos/fleetdm/fleet/pulls`, + { + 'state': 'closed', + 'sort': 'updated', + 'direction': 'desc', + 'per_page': NUMBER_OF_RESULTS_REQUESTED, + 'page': pageNumberForPaginatedResults, + }, + baseHeaders + ).retry(); + + // Filter the PRs we recieved from Github using the pull request's merged_at date. + let resultsToAdd = closedPullRequests.filter((pullRequest)=>{ + return threeWeeksAgo <= new Date(pullRequest.merged_at); + }); + + // Add the filtered array of PRs to the array of all pull requests merged in the past three weeks. + pullRequestsMergedInThePastThreeWeeks = pullRequestsMergedInThePastThreeWeeks.concat(resultsToAdd); + // Stop when we've recieved 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)=>{ + // 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 + 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. + let timeFromCommitToMergeInMS = pullRequestMergedOn - firstCommitAt; + // Convert the miliseconds to days and add the value to the daysSincePullRequestsWereOpened array. + let timeFromFirstCommitInDays = timeFromCommitToMergeInMS / ONE_DAY_IN_MILLISECONDS; + commitToMergeTimesInDays.push(timeFromFirstCommitInDays); + }); + + }, + // ██████╗ ██████╗ ███████╗███╗ ██╗ ██████╗ ██████╗ ███████╗ + // ██╔═══██╗██╔══██╗██╔════╝████╗ ██║ ██╔══██╗██╔══██╗██╔════╝ + // ██║ ██║██████╔╝█████╗ ██╔██╗ ██║ ██████╔╝██████╔╝███████╗ + // ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ██╔═══╝ ██╔══██╗╚════██║ + // ╚██████╔╝██║ ███████╗██║ ╚████║ ██║ ██║ ██║███████║ + // ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ + // + async()=>{ + let pullRequestResultsPageNumber = 0; + let allOpenPullRequests = []; + // 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. + await sails.helpers.flow.until(async ()=>{ + // Increment the page of results we're requesting. + pullRequestResultsPageNumber += 1; + let pullRequests = await sails.helpers.http.get( + `https://api.github.com/repos/fleetdm/fleet/pulls`, + { + 'state': 'open', + 'per_page': NUMBER_OF_RESULTS_REQUESTED, + 'page': pullRequestResultsPageNumber, + }, + baseHeaders + ).retry(); + // Add the results to the array of results. + allOpenPullRequests = allOpenPullRequests.concat(pullRequests); + // If we recieved 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) { + // 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. + let timeOpenInMS = Math.abs(todaysDate - pullRequestOpenedOn); + // Convert the miliseconds to days and add the value to the daysSincePullRequestsWereOpened array + let timeOpenInDays = timeOpenInMS / ONE_DAY_IN_MILLISECONDS; + daysSincePullRequestsWereOpened.push(timeOpenInDays); + } + + } + + ]); + + // Get the averages from the arrays of results. + let averageNumberOfDaysBugsAreOpenFor = Math.round(_.sum(daysSinceBugsWereOpened)/daysSinceBugsWereOpened.length); + let averageNumberOfDaysFromCommitToMerge = Math.round(_.sum(commitToMergeTimesInDays)/commitToMergeTimesInDays.length); + let averageDaysPullRequestsAreOpenFor = Math.round(_.sum(daysSincePullRequestsWereOpened)/daysSincePullRequestsWereOpened.length); + + // Log the results + sails.log(` + Bugs: + --------------------------- + Number of open issues with the "bug" label: ${daysSinceBugsWereOpened.length} + Average open time: ${averageNumberOfDaysBugsAreOpenFor} days. + + + Closed pull requests: + --------------------------- + Number of pull requests merged in the past three weeks: ${commitToMergeTimesInDays.length} + Average time from first commit to merge: ${averageNumberOfDaysFromCommitToMerge} days. + + + Open pull requests + --------------------------- + Number of open pull requests in the fleetdm/fleet Github repo: ${daysSincePullRequestsWereOpened.length} + Average open time: ${averageDaysPullRequestsAreOpenFor} days.`); + } + +}; +