Skip to content

Commit

Permalink
feat: add issue response time metrics and rate limit info
Browse files Browse the repository at this point in the history
  • Loading branch information
ajhenry committed Jan 30, 2024
1 parent bac1f43 commit 893e1f6
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 8 deletions.
94 changes: 90 additions & 4 deletions ts-backend/src/fetchers/issues.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Fetchers for issue & pull request data and metrics

import { Repository } from "@octokit/graphql-schema";
import { Config, Fetcher } from "..";
import { CustomOctokit } from "../lib/octokit";

Expand Down Expand Up @@ -122,11 +123,90 @@ const calculateIssueMetricsPerRepo = async (
};
};

export const addIssueResponseTimeData: Fetcher = async (
result,
octokit,
config
const calculateIssueResponseTime = async (
repoName: string,
octokit: CustomOctokit,
config: Config
) => {
const result = await octokit.graphql.paginate<{ repository: Repository }>(
`
query ($cursor: String, $organization: String!, $repoName: String!, $since: DateTime!) {
repository(owner: $organization, name:$repoName) {
issues(first: 100, after: $cursor, filterBy: {since: $since}) {
pageInfo {
hasNextPage
endCursor
}
nodes {
createdAt
comments(first: 1) {
totalCount
nodes {
createdAt
}
}
}
}
}
}
`,
{
organization: config.organization,
repoName: repoName,
since: config.since,
}
);

// Check if there are any issues at all
if (
!result.repository ||
!result.repository.issues.nodes ||
result.repository.issues.nodes?.length === 0
) {
return {
issuesCount: 0,
issuesResponseAverageAge: 0,
issuesResponseMedianAge: 0,
};
}

// Filter out issues without comments
const issues = result.repository.issues.nodes.filter(
(issue) => issue!.comments.totalCount > 0
);

const issuesCount = issues.length;

// Calculate the response time for each issue
const issuesResponseTime = issues.map((issue) => {
const createdAt = new Date(issue!.createdAt);
const firstCommentAt = new Date(issue!.comments!.nodes?.[0]!.createdAt);
return firstCommentAt.getTime() - createdAt.getTime();
});

// Sort them based on response time
issuesResponseTime.sort((a, b) => a - b);

// Calculate the average
const issuesTotalResponseTime = issuesResponseTime.reduce(
(acc, responseTime) => acc + responseTime,
0
);
const issuesResponseAverageAge =
issuesCount > 0 ? issuesTotalResponseTime / issuesCount : 0;

// Calculate the median
const issuesResponseMedianAge =
issues.length > 0 ? issuesResponseTime[Math.floor(issues.length / 2)] : 0;

return {
issuesCount,
issuesResponseAverageAge,
issuesResponseMedianAge,
};
};

export const addIssueMetricsData: Fetcher = async (result, octokit, config) => {
for (const repoName of Object.keys(result.repositories)) {
const {
issuesCount: openIssuesCount,
Expand All @@ -140,13 +220,19 @@ export const addIssueResponseTimeData: Fetcher = async (
issuesMedianAge: closedIssuesMedianAge,
} = await calculateIssueMetricsPerRepo(repoName, "closed", octokit, config);

const { issuesResponseAverageAge, issuesResponseMedianAge } =
await calculateIssueResponseTime(repoName, octokit, config);

const repo = result.repositories[repoName];
repo.openIssuesCount = openIssuesCount;
repo.openIssuesAverageAge = openIssuesAverageAge;
repo.openIssuesMedianAge = openIssuesMedianAge;
repo.closedIssuesCount = closedIssuesCount;
repo.closedIssuesAverageAge = closedIssuesAverageAge;
repo.closedIssuesMedianAge = closedIssuesMedianAge;
repo.issuesResponseAverageAge = issuesResponseAverageAge;
repo.issuesResponseMedianAge = issuesResponseMedianAge;
}

return result;
};
15 changes: 11 additions & 4 deletions ts-backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import fs from "fs-extra";
import {
addDiscussionData,
addIssueAndPrData,
addIssueResponseTimeData,
addIssueMetricsData,
addMetaToResult,
addOrganizationInfoToResult,
addRepositoriesToResult,
} from "./fetchers";
import { CustomOctokit, personalOctokit } from "./lib/octokit";
import { checkRateLimit, CustomOctokit, personalOctokit } from "./lib/octokit";

export interface Result {
meta: {
Expand Down Expand Up @@ -55,6 +55,8 @@ export interface RepositoryResult {
openIssuesMedianAge: number;
closedIssuesAverageAge: number;
closedIssuesMedianAge: number;
issuesResponseAverageAge: number;
issuesResponseMedianAge: number;
}

export type Fetcher = (
Expand Down Expand Up @@ -100,6 +102,12 @@ const pipeline =
console.log(`🔧 Running fetcher ${fetcher.name}`);
result = await fetcher(result, octokit, config);
console.log(`✨ Finished ${fetcher.name}`);
const res = await checkRateLimit(octokit);
console.log(
`⚙️ Rate limit: ${res.remaining}/${
res.limit
} remaining until ${res.resetDate.toLocaleString()}`
);
}

return result;
Expand All @@ -117,8 +125,7 @@ const result = await pipeline(octokit, config)(
addRepositoriesToResult,
addIssueAndPrData,
addDiscussionData,
addIssueResponseTimeData
addIssueMetricsData
);

console.log(result);
outputResult(result);

0 comments on commit 893e1f6

Please sign in to comment.