@releasehub/cli 1.0.1 → 1.1.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.
Files changed (60) hide show
  1. package/dist/__tests__/ai.test.d.ts +2 -0
  2. package/dist/__tests__/ai.test.d.ts.map +1 -0
  3. package/dist/__tests__/ai.test.js +160 -0
  4. package/dist/__tests__/ai.test.js.map +1 -0
  5. package/dist/__tests__/cost.test.d.ts +2 -0
  6. package/dist/__tests__/cost.test.d.ts.map +1 -0
  7. package/dist/__tests__/cost.test.js +49 -0
  8. package/dist/__tests__/cost.test.js.map +1 -0
  9. package/dist/__tests__/formatters.test.d.ts +2 -0
  10. package/dist/__tests__/formatters.test.d.ts.map +1 -0
  11. package/dist/__tests__/formatters.test.js +133 -0
  12. package/dist/__tests__/formatters.test.js.map +1 -0
  13. package/dist/__tests__/generate.integration.test.d.ts +2 -0
  14. package/dist/__tests__/generate.integration.test.d.ts.map +1 -0
  15. package/dist/__tests__/generate.integration.test.js +162 -0
  16. package/dist/__tests__/generate.integration.test.js.map +1 -0
  17. package/dist/__tests__/github.test.d.ts +2 -0
  18. package/dist/__tests__/github.test.d.ts.map +1 -0
  19. package/dist/__tests__/github.test.js +44 -0
  20. package/dist/__tests__/github.test.js.map +1 -0
  21. package/dist/__tests__/prefilter.test.d.ts +2 -0
  22. package/dist/__tests__/prefilter.test.d.ts.map +1 -0
  23. package/dist/__tests__/prefilter.test.js +58 -0
  24. package/dist/__tests__/prefilter.test.js.map +1 -0
  25. package/dist/commands/ai.d.ts.map +1 -1
  26. package/dist/commands/ai.js +8 -3
  27. package/dist/commands/ai.js.map +1 -1
  28. package/dist/commands/config.d.ts +3 -0
  29. package/dist/commands/config.d.ts.map +1 -0
  30. package/dist/commands/config.js +60 -0
  31. package/dist/commands/config.js.map +1 -0
  32. package/dist/commands/generate.d.ts +2 -0
  33. package/dist/commands/generate.d.ts.map +1 -1
  34. package/dist/commands/generate.js +35 -9
  35. package/dist/commands/generate.js.map +1 -1
  36. package/dist/index.js +2 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/lib/ai.d.ts +3 -1
  39. package/dist/lib/ai.d.ts.map +1 -1
  40. package/dist/lib/ai.js +85 -31
  41. package/dist/lib/ai.js.map +1 -1
  42. package/dist/lib/config.d.ts +3 -1
  43. package/dist/lib/config.d.ts.map +1 -1
  44. package/dist/lib/config.js +11 -1
  45. package/dist/lib/config.js.map +1 -1
  46. package/dist/lib/cost.d.ts +13 -0
  47. package/dist/lib/cost.d.ts.map +1 -0
  48. package/dist/lib/cost.js +29 -0
  49. package/dist/lib/cost.js.map +1 -0
  50. package/dist/lib/errors.d.ts.map +1 -1
  51. package/dist/lib/errors.js +0 -1
  52. package/dist/lib/errors.js.map +1 -1
  53. package/dist/lib/github.d.ts.map +1 -1
  54. package/dist/lib/github.js +3 -2
  55. package/dist/lib/github.js.map +1 -1
  56. package/dist/lib/prefilter.d.ts +8 -0
  57. package/dist/lib/prefilter.d.ts.map +1 -0
  58. package/dist/lib/prefilter.js +34 -0
  59. package/dist/lib/prefilter.js.map +1 -0
  60. package/package.json +11 -3
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ai.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/ai.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,160 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ // parseResponse is not exported — test it indirectly via the output shape
3
+ // We test the logic that surrounds AI calls: prompt building and response parsing
4
+ // ─── buildUserPrompt (extracted logic) ────────────────────────────────────────
5
+ function buildUserPrompt(prs) {
6
+ const list = prs.map(pr => {
7
+ const labels = pr.labels.length ? `\nLabels: ${pr.labels.join(', ')}` : '';
8
+ const issues = pr.linked_issues.length ? `\nLinked issues: ${pr.linked_issues.join(', ')}` : '';
9
+ const body = pr.body ? `\nBody: ${pr.body.slice(0, 300)}` : '';
10
+ return `#${pr.number}: ${pr.title}${labels}${issues}${body}`;
11
+ }).join('\n\n');
12
+ return `Analyze these ${prs.length} pull requests:\n\n${list}`;
13
+ }
14
+ // ─── parseResponse (extracted logic) ──────────────────────────────────────────
15
+ function parseResponse(raw) {
16
+ const cleaned = raw
17
+ .replace(/```(?:json)?\n?/g, '')
18
+ .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '')
19
+ .trim();
20
+ return JSON.parse(cleaned);
21
+ }
22
+ // ─── Tests ────────────────────────────────────────────────────────────────────
23
+ describe('buildUserPrompt', () => {
24
+ it('includes PR number and title', () => {
25
+ const prompt = buildUserPrompt([
26
+ { number: 42, title: 'Fix login bug', body: null, labels: [], linked_issues: [] },
27
+ ]);
28
+ expect(prompt).toContain('#42: Fix login bug');
29
+ });
30
+ it('includes labels when present', () => {
31
+ const prompt = buildUserPrompt([
32
+ { number: 1, title: 'Add feature', body: null, labels: ['enhancement', 'ui'], linked_issues: [] },
33
+ ]);
34
+ expect(prompt).toContain('Labels: enhancement, ui');
35
+ });
36
+ it('omits labels line when empty', () => {
37
+ const prompt = buildUserPrompt([
38
+ { number: 1, title: 'Add feature', body: null, labels: [], linked_issues: [] },
39
+ ]);
40
+ expect(prompt).not.toContain('Labels:');
41
+ });
42
+ it('includes linked issues when present', () => {
43
+ const prompt = buildUserPrompt([
44
+ { number: 1, title: 'Fix', body: null, labels: [], linked_issues: ['#10', '#11'] },
45
+ ]);
46
+ expect(prompt).toContain('Linked issues: #10, #11');
47
+ });
48
+ it('truncates body to 300 chars', () => {
49
+ const longBody = 'x'.repeat(500);
50
+ const prompt = buildUserPrompt([
51
+ { number: 1, title: 'Fix', body: longBody, labels: [], linked_issues: [] },
52
+ ]);
53
+ const bodyLine = prompt.split('\n').find(l => l.startsWith('Body:'));
54
+ expect(bodyLine.length).toBeLessThanOrEqual(310);
55
+ });
56
+ it('states correct PR count in header', () => {
57
+ const prs = [
58
+ { number: 1, title: 'A', body: null, labels: [], linked_issues: [] },
59
+ { number: 2, title: 'B', body: null, labels: [], linked_issues: [] },
60
+ { number: 3, title: 'C', body: null, labels: [], linked_issues: [] },
61
+ ];
62
+ const prompt = buildUserPrompt(prs);
63
+ expect(prompt).toContain('Analyze these 3 pull requests');
64
+ });
65
+ });
66
+ describe('parseResponse', () => {
67
+ it('parses clean JSON array', () => {
68
+ const raw = JSON.stringify([{ category: 'bugfix', visible: true }]);
69
+ const result = parseResponse(raw);
70
+ expect(result).toHaveLength(1);
71
+ expect(result[0].category).toBe('bugfix');
72
+ });
73
+ it('strips markdown code fences', () => {
74
+ const raw = '```json\n[{"category":"feature"}]\n```';
75
+ const result = parseResponse(raw);
76
+ expect(result[0].category).toBe('feature');
77
+ });
78
+ it('strips code fences without language tag', () => {
79
+ const raw = '```\n[{"category":"bugfix"}]\n```';
80
+ const result = parseResponse(raw);
81
+ expect(result[0].category).toBe('bugfix');
82
+ });
83
+ it('handles multiple items', () => {
84
+ const items = [
85
+ { category: 'feature', visible: true },
86
+ { category: 'internal', visible: false },
87
+ ];
88
+ const result = parseResponse(JSON.stringify(items));
89
+ expect(result).toHaveLength(2);
90
+ });
91
+ it('throws on invalid JSON', () => {
92
+ expect(() => parseResponse('not json')).toThrow();
93
+ });
94
+ });
95
+ // ─── Invalid key error detection (Gemini regex pattern) ───────────────────────
96
+ describe('Gemini invalid key detection', () => {
97
+ const invalidKeyPattern = /api.key.not.valid|api_key_invalid|401|403/i;
98
+ it('matches "API key not valid" message', () => {
99
+ expect(invalidKeyPattern.test('API key not valid. Please pass a valid API key.')).toBe(true);
100
+ });
101
+ it('matches api_key_invalid message', () => {
102
+ expect(invalidKeyPattern.test('api_key_invalid')).toBe(true);
103
+ });
104
+ it('matches 401 status in message', () => {
105
+ expect(invalidKeyPattern.test('Request failed with status 401')).toBe(true);
106
+ });
107
+ it('matches 403 status in message', () => {
108
+ expect(invalidKeyPattern.test('403 Forbidden')).toBe(true);
109
+ });
110
+ it('does not match unrelated errors', () => {
111
+ expect(invalidKeyPattern.test('Network timeout')).toBe(false);
112
+ expect(invalidKeyPattern.test('Unexpected response format')).toBe(false);
113
+ });
114
+ });
115
+ // ─── Gemini provider mock ──────────────────────────────────────────────────────
116
+ vi.mock('@google/generative-ai', () => ({
117
+ GoogleGenerativeAI: vi.fn().mockImplementation(() => ({
118
+ getGenerativeModel: vi.fn().mockReturnValue({
119
+ generateContent: vi.fn().mockResolvedValue({
120
+ response: {
121
+ text: () => JSON.stringify([
122
+ {
123
+ original_title: 'Add search',
124
+ rewritten_title: 'You can now search across all items',
125
+ category: 'feature',
126
+ visible: true,
127
+ confidence: 0.95,
128
+ reasoning: 'New user-facing capability',
129
+ },
130
+ ]),
131
+ },
132
+ }),
133
+ }),
134
+ })),
135
+ }));
136
+ vi.mock('../lib/config.js', () => ({
137
+ getActiveProvider: vi.fn(() => 'gemini'),
138
+ getActiveAIKey: vi.fn(() => 'AIza-test-key'),
139
+ }));
140
+ describe('analyzeWithGemini (via analyzePullRequests)', () => {
141
+ it('calls GoogleGenerativeAI with the active key', async () => {
142
+ const { GoogleGenerativeAI } = await import('@google/generative-ai');
143
+ const { analyzePullRequests } = await import('../lib/ai.js');
144
+ await analyzePullRequests([
145
+ { number: 1, title: 'Add search', body: null, labels: [], author: 'alice', merged_at: '', url: '', linked_issues: [] },
146
+ ]);
147
+ expect(GoogleGenerativeAI).toHaveBeenCalledWith('AIza-test-key');
148
+ });
149
+ it('returns parsed AnalyzedChange from Gemini response', async () => {
150
+ const { analyzePullRequests } = await import('../lib/ai.js');
151
+ const result = await analyzePullRequests([
152
+ { number: 1, title: 'Add search', body: null, labels: [], author: 'alice', merged_at: '', url: '', linked_issues: [] },
153
+ ]);
154
+ expect(result.changes).toHaveLength(1);
155
+ expect(result.changes[0].category).toBe('feature');
156
+ expect(result.changes[0].visible).toBe(true);
157
+ expect(result.changes[0].rewritten_title).toContain('search');
158
+ });
159
+ });
160
+ //# sourceMappingURL=ai.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.test.js","sourceRoot":"","sources":["../../src/__tests__/ai.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cost.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cost.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,49 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { estimateCost, formatCostEstimate } from '../lib/cost.js';
3
+ describe('estimateCost', () => {
4
+ it('returns zero cost for zero PRs', () => {
5
+ const result = estimateCost(0, 'anthropic');
6
+ expect(result.inputTokens).toBeGreaterThan(0); // system prompt still counts
7
+ expect(result.outputTokens).toBe(0);
8
+ expect(result.costUsd).toBeGreaterThanOrEqual(0);
9
+ });
10
+ it('scales linearly with PR count', () => {
11
+ const one = estimateCost(1, 'anthropic');
12
+ const ten = estimateCost(10, 'anthropic');
13
+ expect(ten.inputTokens).toBeGreaterThan(one.inputTokens);
14
+ expect(ten.outputTokens).toBe(one.outputTokens * 10);
15
+ });
16
+ it('gemini is cheaper than anthropic for same PR count', () => {
17
+ const anthropic = estimateCost(10, 'anthropic');
18
+ const gemini = estimateCost(10, 'gemini');
19
+ expect(gemini.costUsd).toBeLessThan(anthropic.costUsd);
20
+ });
21
+ it('includes correct model name for each provider', () => {
22
+ expect(estimateCost(1, 'anthropic').model).toBe('claude-sonnet-4-5');
23
+ expect(estimateCost(1, 'openai').model).toBe('gpt-4o');
24
+ expect(estimateCost(1, 'gemini').model).toBe('gemini-1.5-flash');
25
+ });
26
+ it('totalTokens equals inputTokens + outputTokens', () => {
27
+ const result = estimateCost(5, 'openai');
28
+ expect(result.totalTokens).toBe(result.inputTokens + result.outputTokens);
29
+ });
30
+ });
31
+ describe('formatCostEstimate', () => {
32
+ it('includes token count and model name', () => {
33
+ const estimate = estimateCost(10, 'anthropic');
34
+ const formatted = formatCostEstimate(estimate);
35
+ expect(formatted).toContain('claude-sonnet-4-5');
36
+ expect(formatted).toContain('tokens');
37
+ });
38
+ it('shows <$0.01 for very cheap estimates', () => {
39
+ const estimate = estimateCost(1, 'gemini');
40
+ const formatted = formatCostEstimate(estimate);
41
+ expect(formatted).toContain('<$0.01');
42
+ });
43
+ it('shows dollar amount for larger estimates', () => {
44
+ const estimate = estimateCost(1000, 'anthropic');
45
+ const formatted = formatCostEstimate(estimate);
46
+ expect(formatted).toMatch(/~\$\d+\.\d{3}/);
47
+ });
48
+ });
49
+ //# sourceMappingURL=cost.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.test.js","sourceRoot":"","sources":["../../src/__tests__/cost.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=formatters.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/formatters.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,133 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { formatGitHubRelease, formatChangelog, formatSlack, formatOutput, } from '../lib/formatters.js';
3
+ // ─── Fixtures ─────────────────────────────────────────────────────────────────
4
+ const change = (overrides = {}) => ({
5
+ original_title: 'fix something',
6
+ rewritten_title: 'Fixed an issue with something',
7
+ category: 'bugfix',
8
+ visible: true,
9
+ confidence: 0.95,
10
+ reasoning: 'user-facing fix',
11
+ ...overrides,
12
+ });
13
+ const feature = (title = 'You can now do something new') => change({ category: 'feature', rewritten_title: title });
14
+ const bugfix = (title = 'Fixed an issue where X happened') => change({ category: 'bugfix', rewritten_title: title });
15
+ const breaking = (title = 'Breaking: old behavior removed') => change({ category: 'breaking', rewritten_title: title });
16
+ const internal = () => change({ category: 'internal', visible: false, rewritten_title: 'Refactored internals' });
17
+ // ─── formatGitHubRelease ──────────────────────────────────────────────────────
18
+ describe('formatGitHubRelease', () => {
19
+ it('renders version heading', () => {
20
+ const out = formatGitHubRelease({ version: 'v1.2.0', changes: [feature()] });
21
+ expect(out).toContain('## v1.2.0');
22
+ });
23
+ it('groups changes under correct headers', () => {
24
+ const out = formatGitHubRelease({
25
+ version: 'v1.0.0',
26
+ changes: [feature(), bugfix(), breaking()],
27
+ });
28
+ expect(out).toContain('### ⚠️ Breaking Changes');
29
+ expect(out).toContain('### ✨ New Features');
30
+ expect(out).toContain('### 🐛 Bug Fixes');
31
+ });
32
+ it('filters out internal changes', () => {
33
+ const out = formatGitHubRelease({
34
+ version: 'v1.0.0',
35
+ changes: [feature(), internal()],
36
+ });
37
+ expect(out).not.toContain('Refactored internals');
38
+ expect(out).toContain('You can now do something new');
39
+ });
40
+ it('shows empty state when all changes are internal', () => {
41
+ const out = formatGitHubRelease({ version: 'v1.0.0', changes: [internal()] });
42
+ expect(out).toContain('No user-facing changes');
43
+ });
44
+ it('includes summary sentence', () => {
45
+ const out = formatGitHubRelease({
46
+ version: 'v1.0.0',
47
+ changes: [feature(), bugfix()],
48
+ });
49
+ expect(out).toContain('This release includes');
50
+ });
51
+ it('puts breaking changes before features', () => {
52
+ const out = formatGitHubRelease({
53
+ version: 'v1.0.0',
54
+ changes: [feature(), breaking()],
55
+ });
56
+ const breakingPos = out.indexOf('Breaking Changes');
57
+ const featurePos = out.indexOf('New Features');
58
+ expect(breakingPos).toBeLessThan(featurePos);
59
+ });
60
+ });
61
+ // ─── formatChangelog ──────────────────────────────────────────────────────────
62
+ describe('formatChangelog', () => {
63
+ it('includes today\'s date', () => {
64
+ const today = new Date().toISOString().split('T')[0];
65
+ const out = formatChangelog({ version: 'v1.0.0', changes: [feature()] });
66
+ expect(out).toContain(today);
67
+ });
68
+ it('renders version in Keep a Changelog format', () => {
69
+ const out = formatChangelog({ version: 'v1.0.0', changes: [feature()] });
70
+ expect(out).toMatch(/## \[v1\.0\.0\]/);
71
+ });
72
+ it('filters out internal changes', () => {
73
+ const out = formatChangelog({ version: 'v1.0.0', changes: [feature(), internal()] });
74
+ expect(out).not.toContain('Refactored internals');
75
+ });
76
+ it('shows empty state when all changes are internal', () => {
77
+ const out = formatChangelog({ version: 'v1.0.0', changes: [internal()] });
78
+ expect(out).toContain('No user-facing changes');
79
+ });
80
+ });
81
+ // ─── formatSlack ──────────────────────────────────────────────────────────────
82
+ describe('formatSlack', () => {
83
+ it('starts with bold version', () => {
84
+ const out = formatSlack({ version: 'v1.0.0', changes: [feature()] });
85
+ expect(out).toContain('*🚀 v1.0.0*');
86
+ });
87
+ it('filters out internal changes', () => {
88
+ const out = formatSlack({ version: 'v1.0.0', changes: [feature(), internal()] });
89
+ expect(out).not.toContain('Refactored internals');
90
+ });
91
+ it('always shows breaking changes', () => {
92
+ const manyFeatures = Array.from({ length: 10 }, (_, i) => feature(`Feature ${i}`));
93
+ const out = formatSlack({
94
+ version: 'v1.0.0',
95
+ changes: [breaking(), ...manyFeatures],
96
+ });
97
+ expect(out).toContain('Breaking: old behavior removed');
98
+ });
99
+ it('caps output at 6 items with overflow message', () => {
100
+ const changes = Array.from({ length: 10 }, (_, i) => feature(`Feature ${i}`));
101
+ const out = formatSlack({ version: 'v1.0.0', changes });
102
+ expect(out).toContain('+ 4 more updates');
103
+ });
104
+ it('shows empty state when all changes are internal', () => {
105
+ const out = formatSlack({ version: 'v1.0.0', changes: [internal()] });
106
+ expect(out).toContain('No user-facing changes');
107
+ });
108
+ it('truncates long titles at 80 chars', () => {
109
+ const longTitle = 'A'.repeat(100);
110
+ const out = formatSlack({ version: 'v1.0.0', changes: [feature(longTitle)] });
111
+ const lines = out.split('\n').filter(l => l.includes('A'));
112
+ expect(lines[0].length).toBeLessThanOrEqual(90); // emoji + space + 80 chars
113
+ });
114
+ });
115
+ // ─── formatOutput ─────────────────────────────────────────────────────────────
116
+ describe('formatOutput', () => {
117
+ it('dispatches to github-release', () => {
118
+ const out = formatOutput('github-release', { version: 'v1.0.0', changes: [feature()] });
119
+ expect(out).toContain('## v1.0.0');
120
+ });
121
+ it('dispatches to changelog', () => {
122
+ const out = formatOutput('changelog', { version: 'v1.0.0', changes: [feature()] });
123
+ expect(out).toContain('[v1.0.0]');
124
+ });
125
+ it('dispatches to slack', () => {
126
+ const out = formatOutput('slack', { version: 'v1.0.0', changes: [feature()] });
127
+ expect(out).toContain('🚀');
128
+ });
129
+ it('throws on unknown format', () => {
130
+ expect(() => formatOutput('unknown', { version: 'v1.0.0', changes: [] })).toThrow('Unknown format');
131
+ });
132
+ });
133
+ //# sourceMappingURL=formatters.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.test.js","sourceRoot":"","sources":["../../src/__tests__/formatters.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=generate.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/generate.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,162 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ // ─── Mocks ────────────────────────────────────────────────────────────────────
3
+ vi.mock('../lib/github.js', () => ({
4
+ fetchPullRequests: vi.fn(),
5
+ publishGitHubRelease: vi.fn(),
6
+ }));
7
+ vi.mock('../lib/ai.js', () => ({
8
+ analyzePullRequests: vi.fn(),
9
+ }));
10
+ vi.mock('../lib/git.js', () => ({
11
+ detectRepo: vi.fn(() => ({ owner: 'testuser', name: 'testrepo' })),
12
+ parseRepo: vi.fn((s) => {
13
+ const [owner, name] = s.split('/');
14
+ return { owner, name };
15
+ }),
16
+ }));
17
+ vi.mock('../lib/config.js', () => ({
18
+ getActiveProvider: vi.fn(() => 'anthropic'),
19
+ getActiveAIKey: vi.fn(() => 'sk-test-key'),
20
+ AI_PROVIDER_LABELS: { anthropic: 'Anthropic (Claude)', openai: 'OpenAI (GPT-4o)', gemini: 'Google (Gemini 1.5 Flash)' },
21
+ }));
22
+ import { fetchPullRequests, publishGitHubRelease } from '../lib/github.js';
23
+ import { analyzePullRequests } from '../lib/ai.js';
24
+ import { formatOutput } from '../lib/formatters.js';
25
+ // ─── Fixtures ─────────────────────────────────────────────────────────────────
26
+ const mockPRs = [
27
+ {
28
+ number: 101,
29
+ title: 'Add dark mode support',
30
+ body: 'Users can now switch to dark mode in settings.',
31
+ labels: ['enhancement'],
32
+ author: 'alice',
33
+ merged_at: '2024-01-15T10:00:00Z',
34
+ url: 'https://github.com/testuser/testrepo/pull/101',
35
+ linked_issues: ['#55'],
36
+ },
37
+ {
38
+ number: 102,
39
+ title: 'Fix login timeout issue',
40
+ body: 'Fixes #60 — users were getting logged out after 5 minutes.',
41
+ labels: ['bug'],
42
+ author: 'bob',
43
+ merged_at: '2024-01-16T12:00:00Z',
44
+ url: 'https://github.com/testuser/testrepo/pull/102',
45
+ linked_issues: ['#60'],
46
+ },
47
+ {
48
+ number: 103,
49
+ title: 'Bump lodash to 4.17.21',
50
+ body: null,
51
+ labels: ['dependencies'],
52
+ author: 'dependabot',
53
+ merged_at: '2024-01-17T08:00:00Z',
54
+ url: 'https://github.com/testuser/testrepo/pull/103',
55
+ linked_issues: [],
56
+ },
57
+ ];
58
+ const mockChanges = [
59
+ {
60
+ original_title: 'Add dark mode support',
61
+ rewritten_title: 'You can now switch to dark mode in settings',
62
+ category: 'feature',
63
+ visible: true,
64
+ confidence: 0.97,
65
+ reasoning: 'New user-facing capability',
66
+ },
67
+ {
68
+ original_title: 'Fix login timeout issue',
69
+ rewritten_title: 'Fixed an issue where users were logged out unexpectedly',
70
+ category: 'bugfix',
71
+ visible: true,
72
+ confidence: 0.95,
73
+ reasoning: 'User-facing bug fix',
74
+ },
75
+ {
76
+ original_title: 'Bump lodash to 4.17.21',
77
+ rewritten_title: 'Bump lodash to 4.17.21',
78
+ category: 'internal',
79
+ visible: false,
80
+ confidence: 0.99,
81
+ reasoning: 'Dependency update with no user impact',
82
+ },
83
+ ];
84
+ // ─── Tests ────────────────────────────────────────────────────────────────────
85
+ describe('generate pipeline — integration', () => {
86
+ beforeEach(() => {
87
+ vi.clearAllMocks();
88
+ vi.mocked(fetchPullRequests).mockResolvedValue(mockPRs);
89
+ vi.mocked(analyzePullRequests).mockResolvedValue({ changes: mockChanges, prefilteredCount: 0 });
90
+ });
91
+ it('fetches PRs with correct repo and range', async () => {
92
+ await vi.mocked(fetchPullRequests)({ owner: 'testuser', name: 'testrepo' }, 'v1.0.0', 'v1.1.0');
93
+ expect(fetchPullRequests).toHaveBeenCalledWith({ owner: 'testuser', name: 'testrepo' }, 'v1.0.0', 'v1.1.0');
94
+ });
95
+ it('passes fetched PRs to AI analysis', async () => {
96
+ const prs = await vi.mocked(fetchPullRequests)({ owner: 'testuser', name: 'testrepo' }, 'v1.0.0', 'v1.1.0');
97
+ await vi.mocked(analyzePullRequests)(prs);
98
+ expect(analyzePullRequests).toHaveBeenCalledWith(mockPRs);
99
+ });
100
+ it('filters internal changes out of formatted output', () => {
101
+ const output = formatOutput('github-release', { version: 'v1.1.0', changes: mockChanges });
102
+ expect(output).not.toContain('lodash');
103
+ expect(output).not.toContain('Bump');
104
+ });
105
+ it('includes feature and bugfix in formatted output', () => {
106
+ const output = formatOutput('github-release', { version: 'v1.1.0', changes: mockChanges });
107
+ expect(output).toContain('dark mode');
108
+ expect(output).toContain('logged out unexpectedly');
109
+ });
110
+ it('full pipeline: fetch → analyze → format produces valid github-release output', async () => {
111
+ const prs = await vi.mocked(fetchPullRequests)({ owner: 'testuser', name: 'testrepo' }, 'v1.0.0', 'v1.1.0');
112
+ const { changes } = await vi.mocked(analyzePullRequests)(prs);
113
+ const output = formatOutput('github-release', { version: 'v1.1.0', changes });
114
+ expect(output).toContain('## v1.1.0');
115
+ expect(output).toContain('### ✨ New Features');
116
+ expect(output).toContain('### 🐛 Bug Fixes');
117
+ expect(output).not.toContain('internal');
118
+ expect(output).not.toContain('lodash');
119
+ });
120
+ it('full pipeline: fetch → analyze → format produces valid slack output', async () => {
121
+ const prs = await vi.mocked(fetchPullRequests)({ owner: 'testuser', name: 'testrepo' }, 'v1.0.0', 'v1.1.0');
122
+ const { changes } = await vi.mocked(analyzePullRequests)(prs);
123
+ const output = formatOutput('slack', { version: 'v1.1.0', changes });
124
+ expect(output).toContain('*🚀 v1.1.0*');
125
+ expect(output).toContain('dark mode');
126
+ expect(output).not.toContain('lodash');
127
+ });
128
+ it('full pipeline: fetch → analyze → format produces valid changelog output', async () => {
129
+ const prs = await vi.mocked(fetchPullRequests)({ owner: 'testuser', name: 'testrepo' }, 'v1.0.0', 'v1.1.0');
130
+ const { changes } = await vi.mocked(analyzePullRequests)(prs);
131
+ const output = formatOutput('changelog', { version: 'v1.1.0', changes });
132
+ const today = new Date().toISOString().split('T')[0];
133
+ expect(output).toContain(`[v1.1.0] — ${today}`);
134
+ expect(output).toContain('dark mode');
135
+ });
136
+ it('publish step receives correctly formatted release body', async () => {
137
+ vi.mocked(publishGitHubRelease).mockResolvedValue({
138
+ id: 1,
139
+ html_url: 'https://github.com/testuser/testrepo/releases/tag/v1.1.0',
140
+ name: 'v1.1.0',
141
+ });
142
+ const prs = await vi.mocked(fetchPullRequests)({ owner: 'testuser', name: 'testrepo' }, 'v1.0.0', 'v1.1.0');
143
+ const { changes } = await vi.mocked(analyzePullRequests)(prs);
144
+ const body = formatOutput('github-release', { version: 'v1.1.0', changes });
145
+ await publishGitHubRelease({ owner: 'testuser', name: 'testrepo' }, 'v1.1.0', body);
146
+ expect(publishGitHubRelease).toHaveBeenCalledWith({ owner: 'testuser', name: 'testrepo' }, 'v1.1.0', expect.stringContaining('## v1.1.0'));
147
+ });
148
+ it('handles empty PR list gracefully', async () => {
149
+ vi.mocked(fetchPullRequests).mockResolvedValue([]);
150
+ const prs = await vi.mocked(fetchPullRequests)({ owner: 'testuser', name: 'testrepo' }, 'v1.0.0', 'v1.1.0');
151
+ expect(prs).toHaveLength(0);
152
+ });
153
+ it('handles all-internal changes gracefully', async () => {
154
+ const allInternal = mockChanges.map(c => ({ ...c, visible: false, category: 'internal' }));
155
+ vi.mocked(analyzePullRequests).mockResolvedValue({ changes: allInternal, prefilteredCount: 0 });
156
+ const prs = await vi.mocked(fetchPullRequests)({ owner: 'testuser', name: 'testrepo' }, 'v1.0.0', 'v1.1.0');
157
+ const { changes } = await vi.mocked(analyzePullRequests)(prs);
158
+ const output = formatOutput('github-release', { version: 'v1.1.0', changes });
159
+ expect(output).toContain('No user-facing changes');
160
+ });
161
+ });
162
+ //# sourceMappingURL=generate.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.integration.test.js","sourceRoot":"","sources":["../../src/__tests__/generate.integration.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAI7D,iFAAiF;AAEjF,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE;IAC1B,oBAAoB,EAAE,EAAE,CAAC,EAAE,EAAE;CAC9B,CAAC,CAAC,CAAA;AAEH,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7B,mBAAmB,EAAE,EAAE,CAAC,EAAE,EAAE;CAC7B,CAAC,CAAC,CAAA;AAEH,EAAE,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;IAC9B,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAClE,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAS,EAAE,EAAE;QAC7B,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAClC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;IACxB,CAAC,CAAC;CACH,CAAC,CAAC,CAAA;AAEH,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,iBAAiB,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC;IAC3C,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC;IAC1C,kBAAkB,EAAE,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,2BAA2B,EAAE;CACxH,CAAC,CAAC,CAAA;AAEH,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAEnD,iFAAiF;AAEjF,MAAM,OAAO,GAAkB;IAC7B;QACE,MAAM,EAAE,GAAG;QACX,KAAK,EAAE,uBAAuB;QAC9B,IAAI,EAAE,gDAAgD;QACtD,MAAM,EAAE,CAAC,aAAa,CAAC;QACvB,MAAM,EAAE,OAAO;QACf,SAAS,EAAE,sBAAsB;QACjC,GAAG,EAAE,+CAA+C;QACpD,aAAa,EAAE,CAAC,KAAK,CAAC;KACvB;IACD;QACE,MAAM,EAAE,GAAG;QACX,KAAK,EAAE,yBAAyB;QAChC,IAAI,EAAE,4DAA4D;QAClE,MAAM,EAAE,CAAC,KAAK,CAAC;QACf,MAAM,EAAE,KAAK;QACb,SAAS,EAAE,sBAAsB;QACjC,GAAG,EAAE,+CAA+C;QACpD,aAAa,EAAE,CAAC,KAAK,CAAC;KACvB;IACD;QACE,MAAM,EAAE,GAAG;QACX,KAAK,EAAE,wBAAwB;QAC/B,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,CAAC,cAAc,CAAC;QACxB,MAAM,EAAE,YAAY;QACpB,SAAS,EAAE,sBAAsB;QACjC,GAAG,EAAE,+CAA+C;QACpD,aAAa,EAAE,EAAE;KAClB;CACF,CAAA;AAED,MAAM,WAAW,GAAqB;IACpC;QACE,cAAc,EAAE,uBAAuB;QACvC,eAAe,EAAE,6CAA6C;QAC9D,QAAQ,EAAE,SAAS;QACnB,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,IAAI;QAChB,SAAS,EAAE,4BAA4B;KACxC;IACD;QACE,cAAc,EAAE,yBAAyB;QACzC,eAAe,EAAE,yDAAyD;QAC1E,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,IAAI;QAChB,SAAS,EAAE,qBAAqB;KACjC;IACD;QACE,cAAc,EAAE,wBAAwB;QACxC,eAAe,EAAE,wBAAwB;QACzC,QAAQ,EAAE,UAAU;QACpB,OAAO,EAAE,KAAK;QACd,UAAU,EAAE,IAAI;QAChB,SAAS,EAAE,uCAAuC;KACnD;CACF,CAAA;AAED,iFAAiF;AAEjF,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAA;QAClB,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAA;QACvD,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,iBAAiB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC,CAAA;IACjG,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC/F,MAAM,CAAC,iBAAiB,CAAC,CAAC,oBAAoB,CAC5C,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EACvC,QAAQ,EACR,QAAQ,CACT,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC3G,MAAM,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAA;QACzC,MAAM,CAAC,mBAAmB,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAA;IAC3D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,MAAM,GAAG,YAAY,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAA;QAC1F,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;QACtC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;IACtC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,MAAM,GAAG,YAAY,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAA;QAC1F,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QACrC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8EAA8E,EAAE,KAAK,IAAI,EAAE;QAC5F,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC3G,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAA;QAC7D,MAAM,MAAM,GAAG,YAAY,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;QAE7E,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QACrC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAA;QAC9C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAA;QAC5C,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC3G,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAA;QAC7D,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;QAEpE,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QACrC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;QACvF,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC3G,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAA;QAC7D,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;QAExE,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QACpD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,KAAK,EAAE,CAAC,CAAA;QAC/C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,iBAAiB,CAAC;YAChD,EAAE,EAAE,CAAC;YACL,QAAQ,EAAE,0DAA0D;YACpE,IAAI,EAAE,QAAQ;SACf,CAAC,CAAA;QAEF,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC3G,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAA;QAC7D,MAAM,IAAI,GAAG,YAAY,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;QAE3E,MAAM,oBAAoB,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAA;QAEnF,MAAM,CAAC,oBAAoB,CAAC,CAAC,oBAAoB,CAC/C,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EACvC,QAAQ,EACR,MAAM,CAAC,gBAAgB,CAAC,WAAW,CAAC,CACrC,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAA;QAClD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC3G,MAAM,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,WAAW,GAAqB,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,CAAA;QAC5G,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,iBAAiB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC,CAAA;QAE/F,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC3G,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAA;QAC7D,MAAM,MAAM,GAAG,YAAY,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;QAE7E,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAA;IACpD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=github.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/github.test.ts"],"names":[],"mappings":""}