Skip to content

Instantly share code, notes, and snippets.

@raymyers
Last active April 22, 2023 01:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raymyers/2c4a05b08ff00affb0369b50aee7baea to your computer and use it in GitHub Desktop.
Save raymyers/2c4a05b08ff00affb0369b50aee7baea to your computer and use it in GitHub Desktop.
GPT4 generated code to extract metrics from GitHub, NOT debugged
// Warning: This code is LLM output and has NOT been debugged.
const { Octokit } = require("@octokit/rest");
// Initialize the Octokit client
const octokit = new Octokit({ auth: "your_personal_access_token" });
// Variables for your specific repository
const owner = "your_github_username";
const repo = "your_repository_name";
// Helper function to get the previous month's date
function getPreviousMonth(date) {
const newDate = new Date(date);
newDate.setMonth(date.getMonth() - 1);
return newDate;
}
async function main() {
const today = new Date();
let startDate = getPreviousMonth(today);
let endDate = today;
while (startDate > new Date("2022-01-01")) { // Change to your desired start date
try {
const deploymentFrequency = await getDeploymentFrequency(owner, repo, startDate, endDate);
const mergeFrequency = await getMergeFrequency(owner, repo, startDate, endDate);
const reviewTime = await getReviewTime(owner, repo, startDate, endDate);
const leadTimeToChange = await getLeadTimeToChange(owner, repo, startDate, endDate);
console.log(`Metrics for ${startDate.toISOString().slice(0, 7)}:`);
console.log("Deployment Frequency: ", deploymentFrequency);
console.log("Merge Frequency: ", mergeFrequency);
console.log("Review Time: ", reviewTime);
console.log("Lead Time to Change: ", leadTimeToChange);
console.log("\n");
endDate = startDate;
startDate = getPreviousMonth(startDate);
} catch (error) {
console.error("Error: ", error);
}
}
}
async function getDeploymentFrequency(owner, repo, startDate, endDate) {
try {
const deployments = await octokit.paginate(octokit.repos.listDeployments, {
owner,
repo,
per_page: 100,
});
// Filter deployments based on the date range
const deploymentsInRange = deployments.filter((deployment) => {
const deploymentDate = new Date(deployment.created_at);
return deploymentDate >= startDate && deploymentDate < endDate;
});
// Calculate deployment frequency
const deploymentFrequency = deploymentsInRange.length;
return deploymentFrequency;
} catch (error) {
console.error("Error in getDeploymentFrequency: ", error);
}
}
async function getMergeFrequency(owner, repo, startDate, endDate) {
try {
const prs = await octokit.paginate(octokit.pulls.list, {
owner,
repo,
state: "all",
per_page: 100,
});
// Filter PRs based on the date range and merged state
const mergedPrsInRange = prs.filter((pr) => {
const mergedDate = new Date(pr.merged_at);
return pr.merged_at !== null && mergedDate >= startDate && mergedDate < endDate;
});
// Calculate merge frequency
const mergeFrequency = mergedPrsInRange.length;
return mergeFrequency;
} catch (error) {
console.error("Error in getMergeFrequency: ", error);
}
}
async function getReviewTime(owner, repo, startDate, endDate) {
try {
const prs = await octokit.paginate(octokit.pulls.list, {
owner,
repo,
state: "all",
per_page: 100,
});
const reviewTimes = [];
for (const pr of prs) {
const createdAt = new Date(pr.created_at);
if (createdAt >= startDate && createdAt < endDate) {
const reviews = await octokit.paginate(octokit.pulls.listReviews, {
owner,
repo,
pull_number: pr.number,
per_page: 100,
});
if (reviews.length > 0) {
const firstReviewDate = new Date(reviews[0].submitted_at);
const reviewTime = (firstReviewDate - createdAt) / (1000 * 60 * 60); // Convert to hours
reviewTimes.push(reviewTime);
}
}
}
// Calculate average review time
const totalReviewTime = reviewTimes.reduce((sum, time) => sum + time, 0);
const averageReviewTime = reviewTimes.length > 0 ? totalReviewTime / reviewTimes.length : 0;
return averageReviewTime;
} catch (error) {
console.error("Error in getReviewTime: ", error);
}
}
async function getLeadTimeToChange(owner, repo, startDate, endDate) {
try {
const prs = await octokit.paginate(octokit.pulls.list, {
owner,
repo,
state: "all",
per_page: 100,
});
const leadTimes = [];
for (const pr of prs) {
const createdAt = new Date(pr.created_at);
if (pr.merged_at !== null && createdAt >= startDate && createdAt < endDate) {
const commit = await octokit.repos.getCommit({
owner,
repo,
ref: pr.head.sha,
});
const commitDate = new Date(commit.data.commit.committer.date);
const leadTime = (createdAt - commitDate) / (1000 * 60 * 60); // Convert to hours
leadTimes.push(leadTime);
}
}
// Calculate average lead time to change
const totalLeadTime = leadTimes.reduce((sum, time) => sum + time, 0);
const averageLeadTimeToChange = leadTimes.length > 0 ? totalLeadTime / leadTimes.length : 0;
return averageLeadTimeToChange;
} catch (error) {
console.error("Error in getLeadTimeToChange: ", error);
}
}
main();
"Act as an experienced software engineer with knowledge of DevOps metrics and DORA. Can you write a high level implementation of an extraction of deployment frequency, merge frequency, review time, and lead time to change in JavaScript using GitHub and GitHub actions (Octokit.js client)?
For now it's ok to write calls to functions that don't exist yet, we will fill them in later."
"Pretty good but we will need to call this for different periods of time. Lets say that we want this broken out month by month."
"Can you fill in getDeploymentFrequency?"
"Fill in getMergeFrequency"
"Fill in getReviewTime"
"Fill in getLeadTimeToChange"
Revising, saving in updated.js:
"Lets change lead time to mean time from being merged into main to being deployed by GitHub Actions"
"Let's update getReviewTime to mean the time between an PR being opened and merged"
// Revised
async function getLeadTimeToChange(owner, repo, startDate, endDate) {
try {
const prs = await octokit.paginate(octokit.pulls.list, {
owner,
repo,
state: "all",
per_page: 100,
});
const deployments = await octokit.paginate(octokit.repos.listDeployments, {
owner,
repo,
per_page: 100,
});
const leadTimes = [];
for (const pr of prs) {
const mergedAt = new Date(pr.merged_at);
if (pr.merged_at !== null && mergedAt >= startDate && mergedAt < endDate) {
const deployment = deployments.find((deployment) => {
const deploymentDate = new Date(deployment.created_at);
return deployment.sha === pr.merge_commit_sha && deploymentDate > mergedAt;
});
if (deployment) {
const deploymentDate = new Date(deployment.created_at);
const leadTime = (deploymentDate - mergedAt) / (1000 * 60 * 60); // Convert to hours
leadTimes.push(leadTime);
}
}
}
// Calculate average lead time to change
const totalLeadTime = leadTimes.reduce((sum, time) => sum + time, 0);
const averageLeadTimeToChange = leadTimes.length > 0 ? totalLeadTime / leadTimes.length : 0;
return averageLeadTimeToChange;
} catch (error) {
console.error("Error in getLeadTimeToChange: ", error);
}
}
async function getReviewTime(owner, repo, startDate, endDate) {
try {
const prs = await octokit.paginate(octokit.pulls.list, {
owner,
repo,
state: "all",
per_page: 100,
});
const reviewTimes = [];
for (const pr of prs) {
const createdAt = new Date(pr.created_at);
if (pr.merged_at !== null && createdAt >= startDate && createdAt < endDate) {
const mergedAt = new Date(pr.merged_at);
const reviewTime = (mergedAt - createdAt) / (1000 * 60 * 60); // Convert to hours
reviewTimes.push(reviewTime);
}
}
// Calculate average review time
const totalReviewTime = reviewTimes.reduce((sum, time) => sum + time, 0);
const averageReviewTime = reviewTimes.length > 0 ? totalReviewTime / reviewTimes.length : 0;
return averageReviewTime;
} catch (error) {
console.error("Error in getReviewTime: ", error);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment