github-workhours
Version:
Analyze GitHub commit patterns to determine after-hours activity
119 lines (111 loc) • 3.79 kB
JavaScript
const { program } = require('commander');
const { subDays, subMonths, subYears } = require('date-fns');
const { analyzeWorkHours, closeCache } = require('./analyzer');
program
.name('github-workhours')
.description('Analyze GitHub commit patterns to determine after-hours activity')
.option('-o, --org <org>', 'GitHub organization name (or set GITHUB_ORG env var)')
.option('-s, --since <since>', 'Start date (ISO format or duration like "2 months", "2mo", "2y", "2w", "2d")')
.option('-u, --until <until>', 'End date (ISO format or duration like "1 month", "1mo", "1y", "1w", "1d")')
.option('-t, --token <token>', 'GitHub Personal Access Token (or set GITHUB_TOKEN env var)')
.version('1.0.0')
.parse(process.argv);
const options = program.opts();
const org = options.org || process.env.GITHUB_ORG;
const token = options.token || process.env.GITHUB_TOKEN;
// parse since flag (ISO date or natural language duration like "2 months" or "2y")
let since;
if (options.since) {
// Support both full words and shorthand notations (y, mo, w, d), with or without spaces
const nlMatch = options.since.match(/^(\d+)\s*(d|day|days|w|week|weeks|mo|month|months|y|year|years)$/i);
if (nlMatch) {
const num = parseInt(nlMatch[1], 10);
const unit = nlMatch[2].toLowerCase();
switch (unit) {
case 'd':
case 'day':
case 'days':
since = subDays(new Date(), num).toISOString();
break;
case 'w':
case 'week':
case 'weeks':
// Convert weeks to days (1 week = 7 days)
since = subDays(new Date(), num * 7).toISOString();
break;
case 'mo':
case 'month':
case 'months':
since = subMonths(new Date(), num).toISOString();
break;
case 'y':
case 'year':
case 'years':
since = subYears(new Date(), num).toISOString();
break;
}
} else {
since = options.since;
}
}
// parse until flag with the same natural language support as since
let until;
if (options.until) {
// Support both full words and shorthand notations (y, mo, w, d), with or without spaces
const nlMatch = options.until.match(/^(\d+)\s*(d|day|days|w|week|weeks|mo|month|months|y|year|years)$/i);
if (nlMatch) {
const num = parseInt(nlMatch[1], 10);
const unit = nlMatch[2].toLowerCase();
switch (unit) {
case 'd':
case 'day':
case 'days':
until = subDays(new Date(), num).toISOString();
break;
case 'w':
case 'week':
case 'weeks':
// Convert weeks to days (1 week = 7 days)
until = subDays(new Date(), num * 7).toISOString();
break;
case 'mo':
case 'month':
case 'months':
until = subMonths(new Date(), num).toISOString();
break;
case 'y':
case 'year':
case 'years':
until = subYears(new Date(), num).toISOString();
break;
}
} else {
until = options.until;
}
}
if (!org) {
console.error('Error: Organization name is required. Provide via --org or GITHUB_ORG env var.');
process.exit(1);
}
if (!token) {
console.error('Error: GitHub token is required. Provide via --token or GITHUB_TOKEN env var.');
process.exit(1);
}
(async () => {
const { default: ora } = await import('ora');
const spinner = ora(`Analyzing commits for organization: ${org}`).start();
try {
const result = await analyzeWorkHours({ org, since, until, token });
spinner.succeed('Analysis complete');
console.log(JSON.stringify(result, null, 2));
} catch (error) {
spinner.fail('Analysis failed');
console.error(error.message);
process.exit(1);
} finally {
// Close the cache to prevent hanging processes
await closeCache();
}
})();
;