specweave 0.6.8 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/README.md +1 -1
- package/CLAUDE.md +903 -99
- package/README.md +143 -207
- package/bin/specweave.js +67 -0
- package/dist/cli/commands/abandon.d.ts +13 -0
- package/dist/cli/commands/abandon.d.ts.map +1 -0
- package/dist/cli/commands/abandon.js +15 -0
- package/dist/cli/commands/abandon.js.map +1 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +94 -18
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/pause.d.ts +13 -0
- package/dist/cli/commands/pause.d.ts.map +1 -0
- package/dist/cli/commands/pause.js +15 -0
- package/dist/cli/commands/pause.js.map +1 -0
- package/dist/cli/commands/qa.d.ts +54 -0
- package/dist/cli/commands/qa.d.ts.map +1 -0
- package/dist/cli/commands/qa.js +98 -0
- package/dist/cli/commands/qa.js.map +1 -0
- package/dist/cli/commands/resume.d.ts +12 -0
- package/dist/cli/commands/resume.d.ts.map +1 -0
- package/dist/cli/commands/resume.js +14 -0
- package/dist/cli/commands/resume.js.map +1 -0
- package/dist/cli/commands/status.d.ts +12 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +23 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/ado.d.ts +57 -0
- package/dist/cli/helpers/issue-tracker/ado.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/ado.js +223 -0
- package/dist/cli/helpers/issue-tracker/ado.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/github.d.ts +65 -0
- package/dist/cli/helpers/issue-tracker/github.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/github.js +284 -0
- package/dist/cli/helpers/issue-tracker/github.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/index.d.ts +22 -0
- package/dist/cli/helpers/issue-tracker/index.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/index.js +270 -0
- package/dist/cli/helpers/issue-tracker/index.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/jira.d.ts +61 -0
- package/dist/cli/helpers/issue-tracker/jira.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/jira.js +265 -0
- package/dist/cli/helpers/issue-tracker/jira.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/types.d.ts +86 -0
- package/dist/cli/helpers/issue-tracker/types.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/types.js +16 -0
- package/dist/cli/helpers/issue-tracker/types.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/utils.d.ts +103 -0
- package/dist/cli/helpers/issue-tracker/utils.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/utils.js +240 -0
- package/dist/cli/helpers/issue-tracker/utils.js.map +1 -0
- package/dist/core/increment/limits.d.ts +68 -0
- package/dist/core/increment/limits.d.ts.map +1 -0
- package/dist/core/increment/limits.js +224 -0
- package/dist/core/increment/limits.js.map +1 -0
- package/dist/core/increment/metadata-manager.d.ts +114 -0
- package/dist/core/increment/metadata-manager.d.ts.map +1 -0
- package/dist/core/increment/metadata-manager.js +320 -0
- package/dist/core/increment/metadata-manager.js.map +1 -0
- package/dist/core/increment/status-commands.d.ts +43 -0
- package/dist/core/increment/status-commands.d.ts.map +1 -0
- package/dist/core/increment/status-commands.js +277 -0
- package/dist/core/increment/status-commands.js.map +1 -0
- package/dist/core/plugin-detector.d.ts +1 -0
- package/dist/core/plugin-detector.d.ts.map +1 -1
- package/dist/core/plugin-detector.js +25 -0
- package/dist/core/plugin-detector.js.map +1 -1
- package/dist/core/qa/qa-runner.d.ts +16 -0
- package/dist/core/qa/qa-runner.d.ts.map +1 -0
- package/dist/core/qa/qa-runner.js +404 -0
- package/dist/core/qa/qa-runner.js.map +1 -0
- package/dist/core/qa/quality-gate-decider.d.ts +53 -0
- package/dist/core/qa/quality-gate-decider.d.ts.map +1 -0
- package/dist/core/qa/quality-gate-decider.js +268 -0
- package/dist/core/qa/quality-gate-decider.js.map +1 -0
- package/dist/core/qa/risk-calculator.d.ts +126 -0
- package/dist/core/qa/risk-calculator.d.ts.map +1 -0
- package/dist/core/qa/risk-calculator.js +247 -0
- package/dist/core/qa/risk-calculator.js.map +1 -0
- package/dist/core/qa/types.d.ts +315 -0
- package/dist/core/qa/types.d.ts.map +1 -0
- package/dist/core/qa/types.js +8 -0
- package/dist/core/qa/types.js.map +1 -0
- package/dist/core/types/config.d.ts +35 -0
- package/dist/core/types/config.d.ts.map +1 -1
- package/dist/core/types/config.js +16 -0
- package/dist/core/types/config.js.map +1 -1
- package/dist/core/types/increment-metadata.d.ts +120 -0
- package/dist/core/types/increment-metadata.d.ts.map +1 -0
- package/dist/core/types/increment-metadata.js +138 -0
- package/dist/core/types/increment-metadata.js.map +1 -0
- package/dist/hooks/lib/invoke-translator-skill.d.ts +60 -0
- package/dist/hooks/lib/invoke-translator-skill.d.ts.map +1 -0
- package/dist/hooks/lib/invoke-translator-skill.js +201 -0
- package/dist/hooks/lib/invoke-translator-skill.js.map +1 -0
- package/dist/hooks/lib/translate-file.d.ts +59 -0
- package/dist/hooks/lib/translate-file.d.ts.map +1 -0
- package/dist/hooks/lib/translate-file.js +350 -0
- package/dist/hooks/lib/translate-file.js.map +1 -0
- package/dist/locales/en/cli.json +3 -1
- package/dist/metrics/calculators/change-failure-rate.d.ts +22 -0
- package/dist/metrics/calculators/change-failure-rate.d.ts.map +1 -0
- package/dist/metrics/calculators/change-failure-rate.js +70 -0
- package/dist/metrics/calculators/change-failure-rate.js.map +1 -0
- package/dist/metrics/calculators/deployment-frequency.d.ts +20 -0
- package/dist/metrics/calculators/deployment-frequency.d.ts.map +1 -0
- package/dist/metrics/calculators/deployment-frequency.js +61 -0
- package/dist/metrics/calculators/deployment-frequency.js.map +1 -0
- package/dist/metrics/calculators/lead-time.d.ts +22 -0
- package/dist/metrics/calculators/lead-time.d.ts.map +1 -0
- package/dist/metrics/calculators/lead-time.js +82 -0
- package/dist/metrics/calculators/lead-time.js.map +1 -0
- package/dist/metrics/calculators/mttr.d.ts +21 -0
- package/dist/metrics/calculators/mttr.d.ts.map +1 -0
- package/dist/metrics/calculators/mttr.js +60 -0
- package/dist/metrics/calculators/mttr.js.map +1 -0
- package/dist/metrics/dora-calculator.d.ts +24 -0
- package/dist/metrics/dora-calculator.d.ts.map +1 -0
- package/dist/metrics/dora-calculator.js +104 -0
- package/dist/metrics/dora-calculator.js.map +1 -0
- package/dist/metrics/github-client.d.ts +51 -0
- package/dist/metrics/github-client.d.ts.map +1 -0
- package/dist/metrics/github-client.js +133 -0
- package/dist/metrics/github-client.js.map +1 -0
- package/dist/metrics/types.d.ts +112 -0
- package/dist/metrics/types.d.ts.map +1 -0
- package/dist/metrics/types.js +10 -0
- package/dist/metrics/types.js.map +1 -0
- package/dist/metrics/utils/percentile.d.ts +25 -0
- package/dist/metrics/utils/percentile.d.ts.map +1 -0
- package/dist/metrics/utils/percentile.js +46 -0
- package/dist/metrics/utils/percentile.js.map +1 -0
- package/dist/metrics/utils/tier-classifier.d.ts +61 -0
- package/dist/metrics/utils/tier-classifier.d.ts.map +1 -0
- package/dist/metrics/utils/tier-classifier.js +100 -0
- package/dist/metrics/utils/tier-classifier.js.map +1 -0
- package/dist/utils/auth-helpers.d.ts +58 -0
- package/dist/utils/auth-helpers.d.ts.map +1 -0
- package/dist/utils/auth-helpers.js +108 -0
- package/dist/utils/auth-helpers.js.map +1 -0
- package/dist/utils/env-file.d.ts +88 -0
- package/dist/utils/env-file.d.ts.map +1 -0
- package/dist/utils/env-file.js +180 -0
- package/dist/utils/env-file.js.map +1 -0
- package/dist/utils/plugin-detection.d.ts +50 -0
- package/dist/utils/plugin-detection.d.ts.map +1 -0
- package/dist/utils/plugin-detection.js +229 -0
- package/dist/utils/plugin-detection.js.map +1 -0
- package/dist/utils/secrets-loader.d.ts +88 -0
- package/dist/utils/secrets-loader.d.ts.map +1 -0
- package/dist/utils/secrets-loader.js +271 -0
- package/dist/utils/secrets-loader.js.map +1 -0
- package/dist/utils/translation.d.ts +187 -0
- package/dist/utils/translation.d.ts.map +1 -0
- package/dist/utils/translation.js +414 -0
- package/dist/utils/translation.js.map +1 -0
- package/package.json +28 -44
- package/plugins/specweave/.claude-plugin/plugin.json +3 -3
- package/plugins/specweave/agents/pm/AGENT.md +330 -54
- package/plugins/specweave/agents/test-aware-planner/AGENT.md +1035 -0
- package/plugins/specweave/agents/test-aware-planner/templates/README.md +118 -0
- package/plugins/specweave/agents/test-aware-planner/templates/task-non-testable.md.template +24 -0
- package/plugins/specweave/agents/test-aware-planner/templates/task-testable.md.template +53 -0
- package/plugins/specweave/agents/test-aware-planner/templates/tasks-frontmatter.md.template +11 -0
- package/plugins/specweave/commands/README.md +88 -163
- package/plugins/specweave/commands/specweave-abandon.md +314 -0
- package/plugins/specweave/commands/specweave-check-tests.md +546 -0
- package/plugins/specweave/commands/{do.md → specweave-do.md} +5 -7
- package/plugins/specweave/commands/{increment.md → specweave-increment.md} +231 -4
- package/plugins/specweave/commands/specweave-pause.md +189 -0
- package/plugins/specweave/commands/specweave-qa.md +245 -0
- package/plugins/specweave/commands/specweave-resume.md +216 -0
- package/plugins/specweave/commands/specweave-status.md +397 -0
- package/plugins/specweave/commands/specweave-sync-tasks.md +256 -0
- package/plugins/specweave/commands/{translate.md → specweave-translate.md} +3 -3
- package/plugins/specweave/commands/specweave-update-scope.md +351 -0
- package/plugins/specweave/commands/specweave.md +21 -21
- package/plugins/specweave/hooks/post-increment-planning.sh +335 -0
- package/plugins/specweave/hooks/post-task-completion.sh +141 -0
- package/plugins/specweave/skills/SKILLS-INDEX.md +1 -1
- package/plugins/specweave/skills/brownfield-analyzer/SKILL.md +9 -9
- package/plugins/specweave/skills/increment-planner/SKILL.md +400 -212
- package/plugins/specweave/skills/increment-quality-judge-v2/SKILL.md +499 -0
- package/plugins/specweave/skills/plugin-detector/SKILL.md +114 -1
- package/plugins/specweave/skills/project-kickstarter/SKILL.md +74 -1
- package/plugins/specweave/skills/{rfc-generator → spec-generator}/SKILL.md +22 -29
- package/plugins/specweave/skills/specweave-detector/SKILL.md +3 -3
- package/plugins/specweave/skills/specweave-framework/SKILL.md +2 -2
- package/plugins/specweave-ado/.claude-plugin/plugin.json +18 -4
- package/plugins/specweave-ado/agents/ado-manager/AGENT.md +426 -0
- package/plugins/specweave-ado/commands/close-workitem.md +52 -0
- package/plugins/specweave-ado/commands/create-workitem.md +53 -0
- package/plugins/specweave-ado/commands/status.md +53 -0
- package/plugins/specweave-ado/commands/sync.md +55 -0
- package/plugins/specweave-ado/lib/ado-client.ts +361 -0
- package/plugins/specweave-ado/reference/ado-specweave-mapping.md +552 -0
- package/plugins/specweave-ado/skills/ado-sync/SKILL.md +344 -193
- package/plugins/specweave-docs/skills/docusaurus/SKILL.md +73 -0
- package/plugins/specweave-github/agents/github-manager/AGENT.md +49 -0
- package/plugins/specweave-github/commands/{github-close-issue.md → close-issue.md} +1 -1
- package/plugins/specweave-github/commands/{github-create-issue.md → create-issue.md} +1 -1
- package/plugins/specweave-github/commands/{github-status.md → status.md} +1 -1
- package/plugins/specweave-github/commands/{github-sync-tasks.md → sync-tasks.md} +1 -1
- package/plugins/specweave-github/commands/{github-sync.md → sync.md} +1 -1
- package/plugins/specweave-github/reference/github-specweave-mapping.md +377 -0
- package/plugins/specweave-github/skills/github-sync/SKILL.md +11 -3
- package/plugins/specweave-infrastructure/commands/{specweave.monitor-setup.md → monitor-setup.md} +5 -0
- package/plugins/specweave-infrastructure/commands/{specweave.slo-implement.md → slo-implement.md} +5 -0
- package/plugins/specweave-jira/agents/jira-manager/AGENT.md +380 -0
- package/plugins/specweave-jira/commands/{specweave.sync-jira.md → sync.md} +1 -1
- package/plugins/specweave-jira/reference/jira-specweave-mapping.md +508 -0
- package/plugins/specweave-ml/commands/ml-deploy.md +1 -1
- package/plugins/specweave-ml/commands/ml-evaluate.md +1 -1
- package/plugins/specweave-ml/commands/ml-explain.md +1 -1
- package/plugins/specweave-ml/commands/{specweave.ml-pipeline.md → ml-pipeline.md} +5 -0
- package/src/templates/AGENTS.md.template +331 -31
- package/src/templates/CLAUDE.md.template +36 -21
- package/src/templates/COMPLETION-REPORT.template.md +128 -0
- package/src/templates/README.md.template +17 -16
- package/src/templates/docs/README.md +11 -9
- package/src/templates/docs/spec-template.md +229 -0
- package/plugins/specweave/commands/inc.md +0 -85
- package/plugins/specweave/commands/list-increments.md +0 -180
- package/src/adapters/README.md +0 -275
- package/src/adapters/adapter-base.ts +0 -182
- package/src/adapters/adapter-interface.ts +0 -166
- package/src/adapters/adapter-loader.ts +0 -256
- package/src/adapters/agents-md-generator.ts +0 -228
- package/src/adapters/claude/README.md +0 -233
- package/src/adapters/claude/adapter.ts +0 -468
- package/src/adapters/claude-md-generator.ts +0 -377
- package/src/adapters/codex/README.md +0 -105
- package/src/adapters/codex/adapter.ts +0 -333
- package/src/adapters/cursor/.cursor/context/docs-context.md +0 -62
- package/src/adapters/cursor/.cursor/context/increments-context.md +0 -71
- package/src/adapters/cursor/.cursor/context/strategy-context.md +0 -73
- package/src/adapters/cursor/.cursor/context/tests-context.md +0 -89
- package/src/adapters/cursor/README.md +0 -283
- package/src/adapters/cursor/adapter.ts +0 -451
- package/src/adapters/doc-generator.ts +0 -331
- package/src/adapters/gemini/README.md +0 -97
- package/src/adapters/gemini/adapter.ts +0 -298
- package/src/adapters/generic/README.md +0 -277
- package/src/adapters/generic/adapter.ts +0 -378
- package/src/adapters/registry.yaml +0 -187
- /package/plugins/specweave/commands/{costs.md → specweave-costs.md} +0 -0
- /package/plugins/specweave/commands/{done.md → specweave-done.md} +0 -0
- /package/plugins/specweave/commands/{next.md → specweave-next.md} +0 -0
- /package/plugins/specweave/commands/{progress.md → specweave-progress.md} +0 -0
- /package/plugins/specweave/commands/{sync-docs.md → specweave-sync-docs.md} +0 -0
- /package/plugins/specweave/commands/{tdd-cycle.md → specweave-tdd-cycle.md} +0 -0
- /package/plugins/specweave/commands/{tdd-green.md → specweave-tdd-green.md} +0 -0
- /package/plugins/specweave/commands/{tdd-red.md → specweave-tdd-red.md} +0 -0
- /package/plugins/specweave/commands/{tdd-refactor.md → specweave-tdd-refactor.md} +0 -0
- /package/plugins/specweave/commands/{validate.md → specweave-validate.md} +0 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lead Time for Changes Calculator
|
|
3
|
+
*
|
|
4
|
+
* Calculates time from commit to deployment (DORA metric #2)
|
|
5
|
+
* Data source: Git commits + GitHub Releases API
|
|
6
|
+
*/
|
|
7
|
+
import { classifyLeadTime } from '../utils/tier-classifier';
|
|
8
|
+
import { calculatePercentile } from '../utils/percentile';
|
|
9
|
+
/**
|
|
10
|
+
* Calculate Lead Time for Changes
|
|
11
|
+
*
|
|
12
|
+
* Methodology:
|
|
13
|
+
* 1. For each release, find all commits since previous release
|
|
14
|
+
* 2. Calculate time delta (commit date → release date) for each commit
|
|
15
|
+
* 3. Compute average, P50, P90
|
|
16
|
+
* 4. Classify into DORA tier
|
|
17
|
+
*
|
|
18
|
+
* @param releases - Array of GitHub releases (sorted by date desc)
|
|
19
|
+
* @param commits - Array of Git commits
|
|
20
|
+
* @returns Lead time metric
|
|
21
|
+
*/
|
|
22
|
+
export function calculateLeadTime(releases, commits) {
|
|
23
|
+
// Handle zero releases
|
|
24
|
+
if (releases.length === 0) {
|
|
25
|
+
return {
|
|
26
|
+
value: 0,
|
|
27
|
+
unit: 'hours',
|
|
28
|
+
tier: 'N/A',
|
|
29
|
+
p50: 0,
|
|
30
|
+
p90: 0,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// Sort releases by date (newest first)
|
|
34
|
+
const sortedReleases = [...releases].sort((a, b) => new Date(b.published_at).getTime() - new Date(a.published_at).getTime());
|
|
35
|
+
// Calculate lead times for all commits
|
|
36
|
+
const leadTimes = [];
|
|
37
|
+
sortedReleases.forEach((release, index) => {
|
|
38
|
+
const releaseDate = new Date(release.published_at);
|
|
39
|
+
const previousReleaseDate = index < sortedReleases.length - 1
|
|
40
|
+
? new Date(sortedReleases[index + 1].published_at)
|
|
41
|
+
: new Date(0); // Beginning of time for first release
|
|
42
|
+
// Find commits between previous release and current release
|
|
43
|
+
const releaseCommits = commits.filter(commit => {
|
|
44
|
+
const commitDate = new Date(commit.commit.author.date);
|
|
45
|
+
return commitDate > previousReleaseDate && commitDate <= releaseDate;
|
|
46
|
+
});
|
|
47
|
+
// Calculate lead time for each commit
|
|
48
|
+
releaseCommits.forEach(commit => {
|
|
49
|
+
const commitDate = new Date(commit.commit.author.date);
|
|
50
|
+
const leadTimeMs = releaseDate.getTime() - commitDate.getTime();
|
|
51
|
+
const leadTimeHours = leadTimeMs / (1000 * 60 * 60); // Convert to hours
|
|
52
|
+
leadTimes.push(leadTimeHours);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
// Handle no commits (edge case)
|
|
56
|
+
if (leadTimes.length === 0) {
|
|
57
|
+
return {
|
|
58
|
+
value: 0,
|
|
59
|
+
unit: 'hours',
|
|
60
|
+
tier: 'N/A',
|
|
61
|
+
p50: 0,
|
|
62
|
+
p90: 0,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// Calculate statistics
|
|
66
|
+
const averageLeadTime = leadTimes.reduce((sum, lt) => sum + lt, 0) / leadTimes.length;
|
|
67
|
+
const p50 = calculatePercentile(leadTimes, 50);
|
|
68
|
+
const p90 = calculatePercentile(leadTimes, 90);
|
|
69
|
+
// Classify tier
|
|
70
|
+
const tier = classifyLeadTime(averageLeadTime);
|
|
71
|
+
// Choose appropriate unit
|
|
72
|
+
const unit = averageLeadTime < 24 ? 'hours' : 'days';
|
|
73
|
+
const value = unit === 'hours' ? averageLeadTime : averageLeadTime / 24;
|
|
74
|
+
return {
|
|
75
|
+
value: Math.round(value * 10) / 10, // Round to 1 decimal
|
|
76
|
+
unit,
|
|
77
|
+
tier,
|
|
78
|
+
p50: Math.round(p50 * 10) / 10,
|
|
79
|
+
p90: Math.round(p90 * 10) / 10,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=lead-time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lead-time.js","sourceRoot":"","sources":["../../../src/metrics/calculators/lead-time.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mean Time to Recovery (MTTR) Calculator
|
|
3
|
+
*
|
|
4
|
+
* Calculates average time to recover from incidents (DORA metric #4)
|
|
5
|
+
* Data source: GitHub Issues with labels "incident" or "production-bug"
|
|
6
|
+
*/
|
|
7
|
+
import { Issue, MTTRMetric } from '../types';
|
|
8
|
+
/**
|
|
9
|
+
* Calculate Mean Time to Recovery (MTTR)
|
|
10
|
+
*
|
|
11
|
+
* Methodology:
|
|
12
|
+
* 1. Find closed issues labeled "incident" or "production-bug"
|
|
13
|
+
* 2. Calculate time from created_at to closed_at for each
|
|
14
|
+
* 3. Compute average, P50, P90
|
|
15
|
+
* 4. Classify into DORA tier
|
|
16
|
+
*
|
|
17
|
+
* @param issues - Array of GitHub issues
|
|
18
|
+
* @returns MTTR metric
|
|
19
|
+
*/
|
|
20
|
+
export declare function calculateMTTR(issues: Issue[]): MTTRMetric;
|
|
21
|
+
//# sourceMappingURL=mttr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mttr.d.ts","sourceRoot":"","sources":["../../../src/metrics/calculators/mttr.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAI7C;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAiDzD"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mean Time to Recovery (MTTR) Calculator
|
|
3
|
+
*
|
|
4
|
+
* Calculates average time to recover from incidents (DORA metric #4)
|
|
5
|
+
* Data source: GitHub Issues with labels "incident" or "production-bug"
|
|
6
|
+
*/
|
|
7
|
+
import { classifyMTTR } from '../utils/tier-classifier';
|
|
8
|
+
import { calculatePercentile } from '../utils/percentile';
|
|
9
|
+
/**
|
|
10
|
+
* Calculate Mean Time to Recovery (MTTR)
|
|
11
|
+
*
|
|
12
|
+
* Methodology:
|
|
13
|
+
* 1. Find closed issues labeled "incident" or "production-bug"
|
|
14
|
+
* 2. Calculate time from created_at to closed_at for each
|
|
15
|
+
* 3. Compute average, P50, P90
|
|
16
|
+
* 4. Classify into DORA tier
|
|
17
|
+
*
|
|
18
|
+
* @param issues - Array of GitHub issues
|
|
19
|
+
* @returns MTTR metric
|
|
20
|
+
*/
|
|
21
|
+
export function calculateMTTR(issues) {
|
|
22
|
+
// Filter closed incidents
|
|
23
|
+
const closedIncidents = issues.filter(issue => issue.state === 'closed' &&
|
|
24
|
+
issue.closed_at !== null &&
|
|
25
|
+
issue.labels.some(label => label.name === 'incident' || label.name === 'production-bug'));
|
|
26
|
+
// Handle zero closed incidents
|
|
27
|
+
if (closedIncidents.length === 0) {
|
|
28
|
+
return {
|
|
29
|
+
value: 0,
|
|
30
|
+
unit: 'minutes',
|
|
31
|
+
tier: 'N/A',
|
|
32
|
+
p50: 0,
|
|
33
|
+
p90: 0,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Calculate recovery times (in minutes)
|
|
37
|
+
const recoveryTimes = closedIncidents.map(incident => {
|
|
38
|
+
const createdAt = new Date(incident.created_at);
|
|
39
|
+
const closedAt = new Date(incident.closed_at);
|
|
40
|
+
const recoveryMs = closedAt.getTime() - createdAt.getTime();
|
|
41
|
+
return recoveryMs / (1000 * 60); // Convert to minutes
|
|
42
|
+
});
|
|
43
|
+
// Calculate statistics
|
|
44
|
+
const averageMTTR = recoveryTimes.reduce((sum, rt) => sum + rt, 0) / recoveryTimes.length;
|
|
45
|
+
const p50 = calculatePercentile(recoveryTimes, 50);
|
|
46
|
+
const p90 = calculatePercentile(recoveryTimes, 90);
|
|
47
|
+
// Classify tier
|
|
48
|
+
const tier = classifyMTTR(averageMTTR);
|
|
49
|
+
// Choose appropriate unit
|
|
50
|
+
const unit = averageMTTR < 60 ? 'minutes' : 'hours';
|
|
51
|
+
const value = unit === 'minutes' ? averageMTTR : averageMTTR / 60;
|
|
52
|
+
return {
|
|
53
|
+
value: Math.round(value * 10) / 10, // Round to 1 decimal
|
|
54
|
+
unit,
|
|
55
|
+
tier,
|
|
56
|
+
p50: Math.round(p50 * 10) / 10,
|
|
57
|
+
p90: Math.round(p90 * 10) / 10,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=mttr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mttr.js","sourceRoot":"","sources":["../../../src/metrics/calculators/mttr.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,MAAe;IAC3C,0BAA0B;IAC1B,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CACnC,KAAK,CAAC,EAAE,CACN,KAAK,CAAC,KAAK,KAAK,QAAQ;QACxB,KAAK,CAAC,SAAS,KAAK,IAAI;QACxB,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CACxB,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,CAC7D,CACJ,CAAC;IAEF,+BAA+B;IAC/B,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO;YACL,KAAK,EAAE,CAAC;YACR,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,KAAK;YACX,GAAG,EAAE,CAAC;YACN,GAAG,EAAE,CAAC;SACP,CAAC;IACJ,CAAC;IAED,wCAAwC;IACxC,MAAM,aAAa,GAAa,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;QAC7D,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAU,CAAC,CAAC;QAC/C,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;QAC5D,OAAO,UAAU,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAE,qBAAqB;IACzD,CAAC,CAAC,CAAC;IAEH,uBAAuB;IACvB,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC;IAC1F,MAAM,GAAG,GAAG,mBAAmB,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,mBAAmB,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAEnD,gBAAgB;IAChB,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAEvC,0BAA0B;IAC1B,MAAM,IAAI,GAAG,WAAW,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,GAAG,EAAE,CAAC;IAElE,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,EAAE,EAAG,qBAAqB;QAC1D,IAAI;QACJ,IAAI;QACJ,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE;QAC9B,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE;KAC/B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* DORA Metrics Calculator
|
|
4
|
+
*
|
|
5
|
+
* Main orchestrator that calculates all 4 DORA metrics
|
|
6
|
+
* Entry point for CLI and GitHub Actions workflow
|
|
7
|
+
*/
|
|
8
|
+
import { GitHubClient } from './github-client';
|
|
9
|
+
import { DORAMetrics } from './types';
|
|
10
|
+
/**
|
|
11
|
+
* Calculate all DORA metrics
|
|
12
|
+
*
|
|
13
|
+
* @param client - GitHub API client
|
|
14
|
+
* @returns Complete DORA metrics
|
|
15
|
+
*/
|
|
16
|
+
export declare function calculateDORAMetrics(client: GitHubClient): Promise<DORAMetrics>;
|
|
17
|
+
/**
|
|
18
|
+
* Write metrics to JSON file
|
|
19
|
+
*
|
|
20
|
+
* @param metrics - DORA metrics
|
|
21
|
+
* @param filePath - Output file path
|
|
22
|
+
*/
|
|
23
|
+
export declare function writeMetricsJSON(metrics: DORAMetrics, filePath: string): void;
|
|
24
|
+
//# sourceMappingURL=dora-calculator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dora-calculator.d.ts","sourceRoot":"","sources":["../../src/metrics/dora-calculator.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAK/C,OAAO,EAAE,WAAW,EAAgB,MAAM,SAAS,CAAC;AAEpD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAyCrF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAY7E"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* DORA Metrics Calculator
|
|
4
|
+
*
|
|
5
|
+
* Main orchestrator that calculates all 4 DORA metrics
|
|
6
|
+
* Entry point for CLI and GitHub Actions workflow
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import { GitHubClient } from './github-client';
|
|
11
|
+
import { calculateDeploymentFrequency } from './calculators/deployment-frequency';
|
|
12
|
+
import { calculateLeadTime } from './calculators/lead-time';
|
|
13
|
+
import { calculateChangeFailureRate } from './calculators/change-failure-rate';
|
|
14
|
+
import { calculateMTTR } from './calculators/mttr';
|
|
15
|
+
/**
|
|
16
|
+
* Calculate all DORA metrics
|
|
17
|
+
*
|
|
18
|
+
* @param client - GitHub API client
|
|
19
|
+
* @returns Complete DORA metrics
|
|
20
|
+
*/
|
|
21
|
+
export async function calculateDORAMetrics(client) {
|
|
22
|
+
// Query data from GitHub (last 30 days)
|
|
23
|
+
const since = new Date();
|
|
24
|
+
since.setDate(since.getDate() - 30);
|
|
25
|
+
console.log('📊 Fetching data from GitHub API...');
|
|
26
|
+
const releases = await client.getReleases(since);
|
|
27
|
+
console.log(` ✓ Found ${releases.length} releases`);
|
|
28
|
+
const commits = releases.length > 0
|
|
29
|
+
? await client.getCommits(releases[0].target_commitish, new Date())
|
|
30
|
+
: [];
|
|
31
|
+
console.log(` ✓ Found ${commits.length} commits`);
|
|
32
|
+
const issues = await client.getIssues(['incident', 'production-bug'], since);
|
|
33
|
+
console.log(` ✓ Found ${issues.length} incidents`);
|
|
34
|
+
// Calculate metrics
|
|
35
|
+
console.log('\n🔢 Calculating DORA metrics...');
|
|
36
|
+
const deploymentFrequency = calculateDeploymentFrequency(releases);
|
|
37
|
+
console.log(` ✓ Deployment Frequency: ${deploymentFrequency.value} ${deploymentFrequency.unit} (${deploymentFrequency.tier})`);
|
|
38
|
+
const leadTime = calculateLeadTime(releases, commits);
|
|
39
|
+
console.log(` ✓ Lead Time: ${leadTime.value} ${leadTime.unit} (${leadTime.tier})`);
|
|
40
|
+
const changeFailureRate = calculateChangeFailureRate(releases, issues);
|
|
41
|
+
console.log(` ✓ Change Failure Rate: ${changeFailureRate.value}% (${changeFailureRate.tier})`);
|
|
42
|
+
const mttr = calculateMTTR(issues);
|
|
43
|
+
console.log(` ✓ MTTR: ${mttr.value} ${mttr.unit} (${mttr.tier})`);
|
|
44
|
+
return {
|
|
45
|
+
timestamp: new Date().toISOString(),
|
|
46
|
+
metrics: {
|
|
47
|
+
deploymentFrequency,
|
|
48
|
+
leadTime,
|
|
49
|
+
changeFailureRate,
|
|
50
|
+
mttr,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Write metrics to JSON file
|
|
56
|
+
*
|
|
57
|
+
* @param metrics - DORA metrics
|
|
58
|
+
* @param filePath - Output file path
|
|
59
|
+
*/
|
|
60
|
+
export function writeMetricsJSON(metrics, filePath) {
|
|
61
|
+
// Ensure directory exists
|
|
62
|
+
const dir = path.dirname(filePath);
|
|
63
|
+
if (!fs.existsSync(dir)) {
|
|
64
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
// Write JSON with pretty formatting
|
|
67
|
+
const json = JSON.stringify(metrics, null, 2);
|
|
68
|
+
fs.writeFileSync(filePath, json, 'utf-8');
|
|
69
|
+
console.log(`\n✅ Metrics written to ${filePath}`);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* CLI Entry Point
|
|
73
|
+
*
|
|
74
|
+
* Run with: npm run metrics:dora
|
|
75
|
+
* Or: ts-node src/metrics/dora-calculator.ts
|
|
76
|
+
*/
|
|
77
|
+
async function main() {
|
|
78
|
+
try {
|
|
79
|
+
// Parse GitHub config from environment
|
|
80
|
+
const token = process.env.GITHUB_TOKEN;
|
|
81
|
+
if (!token) {
|
|
82
|
+
throw new Error('GITHUB_TOKEN environment variable is required');
|
|
83
|
+
}
|
|
84
|
+
const repository = process.env.GITHUB_REPOSITORY || 'anton-abyzov/specweave';
|
|
85
|
+
const [owner, repo] = repository.split('/');
|
|
86
|
+
const config = { token, owner, repo };
|
|
87
|
+
// Calculate metrics
|
|
88
|
+
const client = new GitHubClient(config);
|
|
89
|
+
const metrics = await calculateDORAMetrics(client);
|
|
90
|
+
// Write to file
|
|
91
|
+
const outputPath = path.join(process.cwd(), 'metrics', 'dora-latest.json');
|
|
92
|
+
writeMetricsJSON(metrics, outputPath);
|
|
93
|
+
console.log('\n🎉 DORA metrics calculation complete!');
|
|
94
|
+
process.exit(0);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.error('\n❌ Error calculating DORA metrics:');
|
|
98
|
+
console.error(error);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// ESM module entry point (always run when executed)
|
|
103
|
+
main();
|
|
104
|
+
//# sourceMappingURL=dora-calculator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dora-calculator.js","sourceRoot":"","sources":["../../src/metrics/dora-calculator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub API Client
|
|
3
|
+
*
|
|
4
|
+
* Wrapper around Octokit for fetching DORA metrics data
|
|
5
|
+
* Handles authentication, rate limiting, and error handling
|
|
6
|
+
*/
|
|
7
|
+
import { Release, Commit, Issue, GitHubConfig } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* GitHub API Client for DORA Metrics
|
|
10
|
+
*/
|
|
11
|
+
export declare class GitHubClient {
|
|
12
|
+
private octokit;
|
|
13
|
+
private owner;
|
|
14
|
+
private repo;
|
|
15
|
+
constructor(config: GitHubConfig);
|
|
16
|
+
/**
|
|
17
|
+
* Get releases from last N days
|
|
18
|
+
*
|
|
19
|
+
* @param since - Date to fetch releases from
|
|
20
|
+
* @returns Array of releases
|
|
21
|
+
*/
|
|
22
|
+
getReleases(since: Date): Promise<Release[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Get commits for a specific SHA range
|
|
25
|
+
*
|
|
26
|
+
* @param sha - Commit SHA to start from
|
|
27
|
+
* @param until - Date to fetch commits until
|
|
28
|
+
* @returns Array of commits
|
|
29
|
+
*/
|
|
30
|
+
getCommits(sha: string, until: Date): Promise<Commit[]>;
|
|
31
|
+
/**
|
|
32
|
+
* Get issues with specific labels
|
|
33
|
+
*
|
|
34
|
+
* @param labels - Array of label names to filter by
|
|
35
|
+
* @param since - Date to fetch issues from
|
|
36
|
+
* @returns Array of issues
|
|
37
|
+
*/
|
|
38
|
+
getIssues(labels: string[], since: Date): Promise<Issue[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Handle GitHub API rate limit errors
|
|
41
|
+
*
|
|
42
|
+
* Implements exponential backoff:
|
|
43
|
+
* 1. Check X-RateLimit-Reset header
|
|
44
|
+
* 2. Wait until reset time (max 1 minute)
|
|
45
|
+
* 3. Retry request
|
|
46
|
+
*
|
|
47
|
+
* @param error - GitHub API error
|
|
48
|
+
*/
|
|
49
|
+
private handleRateLimit;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=github-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-client.d.ts","sourceRoot":"","sources":["../../src/metrics/github-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAS/D;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,IAAI,CAAS;gBAET,MAAM,EAAE,YAAY;IAQhC;;;;;OAKG;IACG,WAAW,CAAC,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAsBlD;;;;;;OAMG;IACG,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAoB7D;;;;;;OAMG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAqBhE;;;;;;;;;OASG;YACW,eAAe;CAiB9B"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub API Client
|
|
3
|
+
*
|
|
4
|
+
* Wrapper around Octokit for fetching DORA metrics data
|
|
5
|
+
* Handles authentication, rate limiting, and error handling
|
|
6
|
+
*/
|
|
7
|
+
import { Octokit } from '@octokit/rest';
|
|
8
|
+
/**
|
|
9
|
+
* Sleep utility for exponential backoff
|
|
10
|
+
*/
|
|
11
|
+
function sleep(ms) {
|
|
12
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* GitHub API Client for DORA Metrics
|
|
16
|
+
*/
|
|
17
|
+
export class GitHubClient {
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.octokit = new Octokit({
|
|
20
|
+
auth: config.token,
|
|
21
|
+
});
|
|
22
|
+
this.owner = config.owner;
|
|
23
|
+
this.repo = config.repo;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get releases from last N days
|
|
27
|
+
*
|
|
28
|
+
* @param since - Date to fetch releases from
|
|
29
|
+
* @returns Array of releases
|
|
30
|
+
*/
|
|
31
|
+
async getReleases(since) {
|
|
32
|
+
try {
|
|
33
|
+
const response = await this.octokit.rest.repos.listReleases({
|
|
34
|
+
owner: this.owner,
|
|
35
|
+
repo: this.repo,
|
|
36
|
+
per_page: 100,
|
|
37
|
+
});
|
|
38
|
+
// Filter by date
|
|
39
|
+
return response.data.filter(release => {
|
|
40
|
+
const publishedAt = new Date(release.published_at);
|
|
41
|
+
return publishedAt >= since;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error.status === 403) {
|
|
46
|
+
await this.handleRateLimit(error);
|
|
47
|
+
return this.getReleases(since); // Retry
|
|
48
|
+
}
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get commits for a specific SHA range
|
|
54
|
+
*
|
|
55
|
+
* @param sha - Commit SHA to start from
|
|
56
|
+
* @param until - Date to fetch commits until
|
|
57
|
+
* @returns Array of commits
|
|
58
|
+
*/
|
|
59
|
+
async getCommits(sha, until) {
|
|
60
|
+
try {
|
|
61
|
+
const response = await this.octokit.rest.repos.listCommits({
|
|
62
|
+
owner: this.owner,
|
|
63
|
+
repo: this.repo,
|
|
64
|
+
sha,
|
|
65
|
+
per_page: 100,
|
|
66
|
+
until: until.toISOString(),
|
|
67
|
+
});
|
|
68
|
+
return response.data;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (error.status === 403) {
|
|
72
|
+
await this.handleRateLimit(error);
|
|
73
|
+
return this.getCommits(sha, until); // Retry
|
|
74
|
+
}
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get issues with specific labels
|
|
80
|
+
*
|
|
81
|
+
* @param labels - Array of label names to filter by
|
|
82
|
+
* @param since - Date to fetch issues from
|
|
83
|
+
* @returns Array of issues
|
|
84
|
+
*/
|
|
85
|
+
async getIssues(labels, since) {
|
|
86
|
+
try {
|
|
87
|
+
const response = await this.octokit.rest.issues.listForRepo({
|
|
88
|
+
owner: this.owner,
|
|
89
|
+
repo: this.repo,
|
|
90
|
+
labels: labels.join(','),
|
|
91
|
+
state: 'all', // Include open and closed
|
|
92
|
+
per_page: 100,
|
|
93
|
+
since: since.toISOString(),
|
|
94
|
+
});
|
|
95
|
+
return response.data;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (error.status === 403) {
|
|
99
|
+
await this.handleRateLimit(error);
|
|
100
|
+
return this.getIssues(labels, since); // Retry
|
|
101
|
+
}
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Handle GitHub API rate limit errors
|
|
107
|
+
*
|
|
108
|
+
* Implements exponential backoff:
|
|
109
|
+
* 1. Check X-RateLimit-Reset header
|
|
110
|
+
* 2. Wait until reset time (max 1 minute)
|
|
111
|
+
* 3. Retry request
|
|
112
|
+
*
|
|
113
|
+
* @param error - GitHub API error
|
|
114
|
+
*/
|
|
115
|
+
async handleRateLimit(error) {
|
|
116
|
+
const resetTime = error.response?.headers?.['x-ratelimit-reset'];
|
|
117
|
+
if (resetTime) {
|
|
118
|
+
const resetDate = new Date(parseInt(resetTime) * 1000);
|
|
119
|
+
const now = new Date();
|
|
120
|
+
const waitMs = resetDate.getTime() - now.getTime();
|
|
121
|
+
if (waitMs > 0) {
|
|
122
|
+
const waitSeconds = Math.min(waitMs / 1000, 60); // Max 1 minute
|
|
123
|
+
console.log(`⏳ GitHub API rate limited. Waiting ${waitSeconds}s...`);
|
|
124
|
+
await sleep(waitMs);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Fallback: wait 10 seconds
|
|
129
|
+
await sleep(10000);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=github-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-client.js","sourceRoot":"","sources":["../../src/metrics/github-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DORA Metrics Types
|
|
3
|
+
*
|
|
4
|
+
* TypeScript interfaces for DORA metrics calculation
|
|
5
|
+
* Based on DevOps Research and Assessment (DORA) benchmarks
|
|
6
|
+
*
|
|
7
|
+
* @see https://dora.dev/
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* DORA Performance Tier
|
|
11
|
+
* Based on industry benchmarks from DORA research
|
|
12
|
+
*/
|
|
13
|
+
export type DORAType = 'Elite' | 'High' | 'Medium' | 'Low' | 'N/A';
|
|
14
|
+
/**
|
|
15
|
+
* GitHub Release (from REST API)
|
|
16
|
+
*/
|
|
17
|
+
export interface Release {
|
|
18
|
+
id: number;
|
|
19
|
+
tag_name: string;
|
|
20
|
+
name: string;
|
|
21
|
+
created_at: string;
|
|
22
|
+
published_at: string;
|
|
23
|
+
target_commitish: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* GitHub Commit (from REST API)
|
|
27
|
+
*/
|
|
28
|
+
export interface Commit {
|
|
29
|
+
sha: string;
|
|
30
|
+
commit: {
|
|
31
|
+
author: {
|
|
32
|
+
name: string;
|
|
33
|
+
date: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* GitHub Issue (from REST API)
|
|
39
|
+
*/
|
|
40
|
+
export interface Issue {
|
|
41
|
+
id: number;
|
|
42
|
+
number: number;
|
|
43
|
+
title: string;
|
|
44
|
+
state: 'open' | 'closed';
|
|
45
|
+
labels: Array<{
|
|
46
|
+
name: string;
|
|
47
|
+
}>;
|
|
48
|
+
created_at: string;
|
|
49
|
+
closed_at: string | null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Deployment Frequency Metric
|
|
53
|
+
*/
|
|
54
|
+
export interface DeploymentFrequencyMetric {
|
|
55
|
+
value: number;
|
|
56
|
+
unit: 'deploys/month' | 'deploys/week';
|
|
57
|
+
tier: DORAType;
|
|
58
|
+
description: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Lead Time for Changes Metric
|
|
62
|
+
*/
|
|
63
|
+
export interface LeadTimeMetric {
|
|
64
|
+
value: number;
|
|
65
|
+
unit: 'hours' | 'days';
|
|
66
|
+
tier: DORAType;
|
|
67
|
+
p50: number;
|
|
68
|
+
p90: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Change Failure Rate Metric
|
|
72
|
+
*/
|
|
73
|
+
export interface ChangeFailureRateMetric {
|
|
74
|
+
value: number;
|
|
75
|
+
unit: 'percentage';
|
|
76
|
+
tier: DORAType;
|
|
77
|
+
failedReleases: number;
|
|
78
|
+
totalReleases: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Mean Time to Recovery (MTTR) Metric
|
|
82
|
+
*/
|
|
83
|
+
export interface MTTRMetric {
|
|
84
|
+
value: number;
|
|
85
|
+
unit: 'minutes' | 'hours';
|
|
86
|
+
tier: DORAType;
|
|
87
|
+
p50: number;
|
|
88
|
+
p90: number;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Complete DORA Metrics Output
|
|
92
|
+
*
|
|
93
|
+
* This is the JSON structure written to metrics/dora-latest.json
|
|
94
|
+
*/
|
|
95
|
+
export interface DORAMetrics {
|
|
96
|
+
timestamp: string;
|
|
97
|
+
metrics: {
|
|
98
|
+
deploymentFrequency: DeploymentFrequencyMetric;
|
|
99
|
+
leadTime: LeadTimeMetric;
|
|
100
|
+
changeFailureRate: ChangeFailureRateMetric;
|
|
101
|
+
mttr: MTTRMetric;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* GitHub API Client Configuration
|
|
106
|
+
*/
|
|
107
|
+
export interface GitHubConfig {
|
|
108
|
+
token: string;
|
|
109
|
+
owner: string;
|
|
110
|
+
repo: string;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/metrics/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE;QACN,MAAM,EAAE;YACN,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;SACd,CAAC;KACH,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,eAAe,GAAG,cAAc,CAAC;IACvC,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE;QACP,mBAAmB,EAAE,yBAAyB,CAAC;QAC/C,QAAQ,EAAE,cAAc,CAAC;QACzB,iBAAiB,EAAE,uBAAuB,CAAC;QAC3C,IAAI,EAAE,UAAU,CAAC;KAClB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/metrics/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|