mirror of
https://github.com/trezor/trezor-suite.git
synced 2026-03-05 06:55:13 +01:00
125 lines
3.8 KiB
TypeScript
125 lines
3.8 KiB
TypeScript
import 'dotenv/config';
|
|
import { Octokit } from 'octokit';
|
|
import chalk from 'chalk';
|
|
|
|
if (!process.env.GH_TOKEN) {
|
|
console.log(chalk.red.bold('Missing GH_TOKEN env variable.'));
|
|
console.log(
|
|
chalk.red(
|
|
'Please create a personal access token at https://github.com/settings/tokens and create a .env file with GH_TOKEN=your_token',
|
|
),
|
|
);
|
|
|
|
process.exit(1);
|
|
}
|
|
|
|
const GH_TOKEN = process.env.GH_TOKEN!;
|
|
|
|
// Workflow ID is the name of the workflow file in the .github/workflows directory
|
|
const VALIDATION_WORKFLOW_ID = 'validation.yml';
|
|
|
|
// Number of workflow runs to analyze, should be a multiple of 100
|
|
const NUMBER_OF_WORFLOW_RUNS_TO_ANALYZE = 500;
|
|
|
|
// Create a personal access token at https://github.com/settings/tokens/new?scopes=repo
|
|
const octokit = new Octokit({ auth: GH_TOKEN });
|
|
|
|
type Run = {
|
|
id: number;
|
|
name: string | null | undefined;
|
|
created_at: string;
|
|
time: number;
|
|
timeInMinutes: string;
|
|
};
|
|
|
|
async function getValidationCheckRuns({ pagesToFetch }: { pagesToFetch: number }): Promise<Run[]> {
|
|
if (pagesToFetch < 1) {
|
|
return [];
|
|
}
|
|
|
|
try {
|
|
const response = await octokit.request(
|
|
'GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs',
|
|
{
|
|
owner: 'trezor',
|
|
repo: 'trezor-suite',
|
|
headers: {
|
|
'X-GitHub-Api-Version': '2022-11-28',
|
|
},
|
|
status: 'success',
|
|
page: pagesToFetch,
|
|
per_page: 100,
|
|
workflow_id: VALIDATION_WORKFLOW_ID,
|
|
},
|
|
);
|
|
|
|
const runs: Run[] = response.data.workflow_runs.map(run => ({
|
|
id: run.id,
|
|
name: run.name,
|
|
created_at: run.created_at,
|
|
time:
|
|
(new Date(run.updated_at).getTime() - new Date(run.run_started_at!).getTime()) /
|
|
1000,
|
|
timeInMinutes: (
|
|
(new Date(run.updated_at).getTime() - new Date(run.run_started_at!).getTime()) /
|
|
1000 /
|
|
60
|
|
).toFixed(2),
|
|
}));
|
|
|
|
return [...runs, ...(await getValidationCheckRuns({ pagesToFetch: pagesToFetch - 1 }))];
|
|
} catch (error) {
|
|
console.error(chalk.red('Error fetching validation check runs'), error);
|
|
|
|
return [];
|
|
}
|
|
}
|
|
|
|
const pagesToFetch = Math.ceil(NUMBER_OF_WORFLOW_RUNS_TO_ANALYZE / 100);
|
|
const validationCheckRuns = await getValidationCheckRuns({ pagesToFetch });
|
|
|
|
console.log(
|
|
'Number of successful %s runs: %d, average time: %d minutes',
|
|
VALIDATION_WORKFLOW_ID,
|
|
validationCheckRuns.length,
|
|
(
|
|
validationCheckRuns.reduce((acc, run) => acc + parseFloat(run.timeInMinutes), 0) /
|
|
validationCheckRuns.length
|
|
).toFixed(2),
|
|
);
|
|
|
|
const sortedTimes = validationCheckRuns.map(run => run.time).sort((a: number, b: number) => a - b);
|
|
|
|
// Slowest time of validation check runs
|
|
const p100Time = sortedTimes[sortedTimes.length - 1];
|
|
console.log('Slowest time: %d minutes (%d seconds total)', (p100Time / 60).toFixed(2), p100Time);
|
|
|
|
const P = [0.99, 0.98, 0.95, 0.9];
|
|
|
|
P.forEach(p => {
|
|
const index = Math.floor(sortedTimes.length * p);
|
|
const time = sortedTimes[index];
|
|
console.log(
|
|
'P%d time (%d runs): %d minutes (%d seconds total)',
|
|
p * 100,
|
|
index,
|
|
(time / 60).toFixed(2),
|
|
time,
|
|
);
|
|
});
|
|
|
|
// Fastest time of validation check runs
|
|
const p0Time = sortedTimes[0];
|
|
console.log('Fastest time: %d minutes (%d seconds total)', (p0Time / 60).toFixed(2), p0Time);
|
|
|
|
// Oldest time of validation check runs
|
|
const sortedRuns = validationCheckRuns.sort(
|
|
(a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime(),
|
|
);
|
|
console.log(
|
|
'Oldest run in this batch: %s',
|
|
new Date(sortedRuns[0].created_at).toLocaleString('en-US', {
|
|
timeZone: 'UTC',
|
|
}),
|
|
);
|