Skip to content

Instantly share code, notes, and snippets.

@ggalmazor
Last active September 11, 2024 07:44
Show Gist options
  • Save ggalmazor/bde7bcda0b8e76340b530f1f51c7a4d9 to your computer and use it in GitHub Desktop.
Save ggalmazor/bde7bcda0b8e76340b530f1f51c7a4d9 to your computer and use it in GitHub Desktop.
Computes stats about GitHub Deployments before and after a cutoff datetime.
import { Octokit } from '@octokit/rest';
import { getTime, isBefore, parseISO } from 'date-fns';
const octokit = new Octokit({ auth: 'token foobar' });
const durationSeconds = (a, b) => Math.round((getTime(parseISO(b)) - getTime(parseISO(a))) / 1000);
const isBeforeCutoff = (cutoffISO8601) => {
const cutoff = parseISO(cutoffISO8601);
return (deployment) => isBefore(parseISO(deployment.created_at), cutoff);
};
const not = (fn) => (input) => !fn(input);
const computeDurationSecs = (owner, repo) => async (deployment) => {
const successStatus = (
await octokit.repos.listDeploymentStatuses({ owner, repo, deployment_id: deployment.id })
).data.filter((status) => status.state === 'success')[0];
if (successStatus === undefined) return null;
return durationSeconds(deployment.created_at, successStatus.created_at);
};
const fetchDeploymentsFor = async (owner, repo, environment, totalPages) => {
const deploymentss = await Promise.all(
[...Array(totalPages).keys()].map((n) =>
octokit.repos.listDeployments({ owner, repo, environment, per_page: 100, page: n + 1 }),
),
);
return deploymentss.flatMap((page) => page.data);
};
const computeStats = async (owner, repo, deployments) => {
const durationsSecs = (await Promise.all(deployments.map(computeDurationSecs(owner, repo)))).filter(
(analysis) => analysis !== null,
);
return {
total: deployments.length,
avgDurationSecs: Math.round(durationsSecs.reduce((a, b) => a + b, 0) / durationsSecs.length),
minDurationSecs: Math.min(...durationsSecs),
maxDurationSecs: Math.max(...durationsSecs),
};
};
const printStats = (group, stats) => {
console.log(
`- ${stats.total} ${group} deployments: avg ${stats.avgDurationSecs} secs, min/max: ${stats.minDurationSecs}/${stats.maxDurationSecs} secs`,
);
};
const run = async (owner, repo, environment, cutoffISO8601) => {
const deployments = await fetchDeploymentsFor(owner, repo, environment, 5);
console.log(`Fetched ${deployments.length} deployments for ${environment}:`);
const deploymentBeforeCutoff = isBeforeCutoff(cutoffISO8601);
printStats("old", await computeStats(owner, repo, deployments.filter(deploymentBeforeCutoff)));
printStats("new", await computeStats(owner, repo, deployments.filter(not(deploymentBeforeCutoff))));
};
try {
await run('foo', 'bar', 'baz', '2024-09-10T10:00:00Z');
} catch (e) {
console.error(e);
}
@ggalmazor
Copy link
Author

This script lets you see changes in your GH Deployments after introducing a change to your deployment pipeline. It gets you basic stats (avg, and min/max durations in seconds) for your deployments from the moment they're created to the moment they are marked as successfully completed.

This script can be easily modified to target other events, have more granular filtering of deployments, and produce other stats. References:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment