pipecraft 0.0.0-releaseit → 0.26.0

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 (183) hide show
  1. package/README.md +126 -108
  2. package/dist/cli/index.d.ts +69 -0
  3. package/dist/cli/index.d.ts.map +1 -1
  4. package/dist/cli/index.js +94 -22
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/generators/init.tpl.d.ts +70 -0
  7. package/dist/generators/init.tpl.d.ts.map +1 -1
  8. package/dist/generators/init.tpl.js +100 -8
  9. package/dist/generators/init.tpl.js.map +1 -1
  10. package/dist/generators/workflows.tpl.d.ts +86 -0
  11. package/dist/generators/workflows.tpl.d.ts.map +1 -1
  12. package/dist/generators/workflows.tpl.js +101 -9
  13. package/dist/generators/workflows.tpl.js.map +1 -1
  14. package/dist/templates/actions/calculate-version.yml.tpl.d.ts +47 -0
  15. package/dist/templates/actions/calculate-version.yml.tpl.d.ts.map +1 -1
  16. package/dist/templates/actions/calculate-version.yml.tpl.js +72 -3
  17. package/dist/templates/actions/calculate-version.yml.tpl.js.map +1 -1
  18. package/dist/templates/actions/create-pr.yml.tpl.d.ts +14 -0
  19. package/dist/templates/actions/create-pr.yml.tpl.d.ts.map +1 -1
  20. package/dist/templates/actions/create-pr.yml.tpl.js +22 -2
  21. package/dist/templates/actions/create-pr.yml.tpl.js.map +1 -1
  22. package/dist/templates/actions/create-release.yml.tpl.d.ts +18 -0
  23. package/dist/templates/actions/create-release.yml.tpl.d.ts.map +1 -0
  24. package/dist/templates/actions/create-release.yml.tpl.js +141 -0
  25. package/dist/templates/actions/create-release.yml.tpl.js.map +1 -0
  26. package/dist/templates/actions/create-tag.yml.tpl.d.ts +14 -0
  27. package/dist/templates/actions/create-tag.yml.tpl.d.ts.map +1 -1
  28. package/dist/templates/actions/create-tag.yml.tpl.js +22 -2
  29. package/dist/templates/actions/create-tag.yml.tpl.js.map +1 -1
  30. package/dist/templates/actions/detect-changes.yml.tpl.d.ts +70 -0
  31. package/dist/templates/actions/detect-changes.yml.tpl.d.ts.map +1 -1
  32. package/dist/templates/actions/detect-changes.yml.tpl.js +98 -2
  33. package/dist/templates/actions/detect-changes.yml.tpl.js.map +1 -1
  34. package/dist/templates/actions/manage-branch.yml.tpl.d.ts +14 -0
  35. package/dist/templates/actions/manage-branch.yml.tpl.d.ts.map +1 -1
  36. package/dist/templates/actions/manage-branch.yml.tpl.js +22 -2
  37. package/dist/templates/actions/manage-branch.yml.tpl.js.map +1 -1
  38. package/dist/templates/actions/promote-branch.yml.tpl.d.ts +14 -0
  39. package/dist/templates/actions/promote-branch.yml.tpl.d.ts.map +1 -1
  40. package/dist/templates/actions/promote-branch.yml.tpl.js +50 -7
  41. package/dist/templates/actions/promote-branch.yml.tpl.js.map +1 -1
  42. package/dist/templates/workflows/pipeline-path-based.yml.tpl.d.ts +114 -1
  43. package/dist/templates/workflows/pipeline-path-based.yml.tpl.d.ts.map +1 -1
  44. package/dist/templates/workflows/pipeline-path-based.yml.tpl.js +479 -74
  45. package/dist/templates/workflows/pipeline-path-based.yml.tpl.js.map +1 -1
  46. package/dist/types/index.d.ts +231 -8
  47. package/dist/types/index.d.ts.map +1 -1
  48. package/dist/types/index.js +9 -0
  49. package/dist/types/index.js.map +1 -1
  50. package/dist/utils/ast-path-operations.d.ts.map +1 -1
  51. package/dist/utils/ast-path-operations.js +24 -11
  52. package/dist/utils/ast-path-operations.js.map +1 -1
  53. package/dist/utils/config.d.ts +63 -0
  54. package/dist/utils/config.d.ts.map +1 -1
  55. package/dist/utils/config.js +71 -0
  56. package/dist/utils/config.js.map +1 -1
  57. package/dist/utils/github-setup.d.ts +323 -2
  58. package/dist/utils/github-setup.d.ts.map +1 -1
  59. package/dist/utils/github-setup.js +551 -23
  60. package/dist/utils/github-setup.js.map +1 -1
  61. package/dist/utils/idempotency.d.ts +147 -7
  62. package/dist/utils/idempotency.d.ts.map +1 -1
  63. package/dist/utils/idempotency.js +143 -15
  64. package/dist/utils/idempotency.js.map +1 -1
  65. package/dist/utils/logger.d.ts +134 -0
  66. package/dist/utils/logger.d.ts.map +1 -0
  67. package/dist/utils/logger.js +153 -0
  68. package/dist/utils/logger.js.map +1 -0
  69. package/dist/utils/preflight.d.ts +223 -12
  70. package/dist/utils/preflight.d.ts.map +1 -1
  71. package/dist/utils/preflight.js +216 -16
  72. package/dist/utils/preflight.js.map +1 -1
  73. package/dist/utils/versioning.d.ts +160 -8
  74. package/dist/utils/versioning.d.ts.map +1 -1
  75. package/dist/utils/versioning.js +179 -15
  76. package/dist/utils/versioning.js.map +1 -1
  77. package/package.json +26 -5
  78. package/.claude/settings.local.json +0 -35
  79. package/.github/actions/calculate-version/action.yml +0 -106
  80. package/.github/actions/create-pr/action.yml +0 -122
  81. package/.github/actions/create-release/action.yml +0 -74
  82. package/.github/actions/create-tag/action.yml +0 -94
  83. package/.github/actions/detect-changes/action.yml +0 -62
  84. package/.github/actions/manage-branch/action.yml +0 -113
  85. package/.github/actions/promote-branch/action.yml +0 -352
  86. package/.github/example/workflows/job.analyze.code.yml +0 -26
  87. package/.github/example/workflows/job.analyze.docker.yml +0 -32
  88. package/.github/example/workflows/job.app.api.deploy.yml +0 -127
  89. package/.github/example/workflows/job.app.api.test.yml +0 -102
  90. package/.github/example/workflows/job.app.docs.deploy.yml +0 -40
  91. package/.github/example/workflows/job.app.docs.test.yml +0 -50
  92. package/.github/example/workflows/job.app.web.deploy.yml +0 -96
  93. package/.github/example/workflows/job.app.web.test.yml +0 -49
  94. package/.github/example/workflows/job.changes.yml +0 -82
  95. package/.github/example/workflows/job.create-pr.yml +0 -96
  96. package/.github/example/workflows/job.env-check.yml +0 -43
  97. package/.github/example/workflows/job.fast-forward.yml +0 -103
  98. package/.github/example/workflows/job.lint.yml +0 -64
  99. package/.github/example/workflows/job.pr-name.yml +0 -70
  100. package/.github/example/workflows/job.pr-squash-name.yml +0 -27
  101. package/.github/example/workflows/job.tag.yml +0 -38
  102. package/.github/example/workflows/job.version.yml +0 -99
  103. package/.github/example/workflows/lib.plugin-base.publish.yml +0 -59
  104. package/.github/example/workflows/pipe.yml +0 -178
  105. package/.github/example/workflows/scripts/fastforward.sh +0 -51
  106. package/.github/example/workflows/scripts/pipe-cleaner.sh +0 -70
  107. package/.github/scripts/fastforward.sh +0 -51
  108. package/.github/scripts/pipe-cleaner.sh +0 -70
  109. package/.github/workflows/pipeline.yml +0 -220
  110. package/.github/workflows/pr-title-check.yml +0 -70
  111. package/.github/workflows/publish.yml +0 -39
  112. package/.pipecraftrc.json +0 -78
  113. package/.release-it.cjs +0 -71
  114. package/PIPELINE_TESTING_PLAN.md +0 -499
  115. package/TRUNK_FLOW_PLAN.md +0 -401
  116. package/assets/logo_banner.png +0 -0
  117. package/assets/logo_banner.webp +0 -0
  118. package/docs/USER_JOURNEY_ERRORS.md +0 -352
  119. package/eslint.config.js +0 -77
  120. package/examples/basic-config.json +0 -41
  121. package/examples/monorepo-config.json +0 -49
  122. package/examples/usage.md +0 -289
  123. package/scripts/debug-workflows.sh +0 -339
  124. package/scripts/parse-pipeline.js +0 -29
  125. package/scripts/test-job-order.cjs +0 -140
  126. package/scripts/validate-pipeline.cjs +0 -379
  127. package/scripts/verify-job-order.sh +0 -30
  128. package/src/cli/index.ts +0 -414
  129. package/src/generators/init.tpl.ts +0 -126
  130. package/src/generators/workflows.tpl.ts +0 -80
  131. package/src/templates/actions/calculate-version.yml.tpl.ts +0 -124
  132. package/src/templates/actions/create-pr.yml.tpl.ts +0 -147
  133. package/src/templates/actions/create-tag.yml.tpl.ts +0 -112
  134. package/src/templates/actions/detect-changes.yml.tpl.ts +0 -87
  135. package/src/templates/actions/manage-branch.yml.tpl.ts +0 -132
  136. package/src/templates/actions/promote-branch.yml.tpl.ts +0 -364
  137. package/src/templates/workflows/pipeline-path-based.yml.tpl.ts +0 -706
  138. package/src/types/index.ts +0 -64
  139. package/src/utils/README-ast-path-operations.md +0 -390
  140. package/src/utils/ast-path-operations.ts +0 -581
  141. package/src/utils/config.ts +0 -64
  142. package/src/utils/github-setup.ts +0 -558
  143. package/src/utils/idempotency.ts +0 -215
  144. package/src/utils/preflight.ts +0 -306
  145. package/src/utils/versioning.ts +0 -244
  146. package/tests/README.md +0 -229
  147. package/tests/TEST_STRUCTURE.md +0 -256
  148. package/tests/act/run-act-tests.sh +0 -345
  149. package/tests/debugging/debug-utils.ts +0 -538
  150. package/tests/debugging/debug-workflow.test.ts +0 -339
  151. package/tests/debugging/debug-workflows.sh +0 -339
  152. package/tests/debugging/iterative-debug.ts +0 -652
  153. package/tests/debugging/run-debug-tests.sh +0 -431
  154. package/tests/fixtures/basic-config.json +0 -51
  155. package/tests/fixtures/invalid-config.json +0 -9
  156. package/tests/fixtures/pipeline-generated.yml +0 -235
  157. package/tests/fixtures/pipeline-preserve-comments.yml +0 -245
  158. package/tests/fixtures/pipeline-user-modified.yml +0 -245
  159. package/tests/fixtures/test-config.json +0 -58
  160. package/tests/github-live/README.md +0 -250
  161. package/tests/github-local/JOB_WORKFLOW_TESTS.md +0 -296
  162. package/tests/github-local/README.md +0 -240
  163. package/tests/github-local/run-all-tests.sh +0 -422
  164. package/tests/github-local/test-job-workflows.sh +0 -631
  165. package/tests/github-local/test-pipeline-workflow.sh +0 -440
  166. package/tests/integration/generators.test.ts +0 -578
  167. package/tests/integration/path-based-template.test.ts +0 -510
  168. package/tests/integration/simple-path-based.test.ts +0 -415
  169. package/tests/setup.ts +0 -56
  170. package/tests/unit/ast-path-operations-extended.test.ts +0 -302
  171. package/tests/unit/cli.test.ts +0 -541
  172. package/tests/unit/config-extended.test.ts +0 -412
  173. package/tests/unit/config.test.ts +0 -152
  174. package/tests/unit/github-setup.test.ts +0 -189
  175. package/tests/unit/idempotency-isolated.test.ts +0 -297
  176. package/tests/unit/job-order.test.ts +0 -157
  177. package/tests/unit/pipeline-path-based.test.ts +0 -511
  178. package/tests/unit/validate-pipeline.test.ts +0 -384
  179. package/tests/unit/versioning-extended.test.ts +0 -279
  180. package/tests/unit/versioning.test.ts +0 -241
  181. package/tsconfig.debug.json +0 -17
  182. package/tsconfig.json +0 -28
  183. package/vitest.config.ts +0 -51
@@ -1,538 +0,0 @@
1
- /**
2
- * GitHub Actions Debugging Utilities
3
- *
4
- * This module provides TypeScript utilities for analyzing GitHub Actions
5
- * workflow failures, parsing logs, and generating debugging reports.
6
- */
7
-
8
- import { execSync } from 'child_process';
9
- import { writeFileSync, mkdirSync, existsSync } from 'fs';
10
- import { join } from 'path';
11
-
12
- export interface WorkflowRun {
13
- id: number;
14
- status: string;
15
- conclusion: string | null;
16
- created_at: string;
17
- html_url: string;
18
- workflow_id: number;
19
- head_branch: string;
20
- head_sha: string;
21
- }
22
-
23
- export interface Job {
24
- id: number;
25
- name: string;
26
- status: string;
27
- conclusion: string | null;
28
- html_url: string;
29
- steps: JobStep[];
30
- started_at: string;
31
- completed_at: string | null;
32
- }
33
-
34
- export interface JobStep {
35
- name: string;
36
- status: string;
37
- conclusion: string | null;
38
- number: number;
39
- started_at: string;
40
- completed_at: string | null;
41
- }
42
-
43
- export interface DebugAnalysis {
44
- runId: number;
45
- status: string;
46
- conclusion: string | null;
47
- failedJobs: Job[];
48
- totalJobs: number;
49
- successRate: number;
50
- commonFailurePatterns: string[];
51
- recommendations: string[];
52
- }
53
-
54
- export interface LogAnalysis {
55
- jobId: number;
56
- jobName: string;
57
- errorCount: number;
58
- warningCount: number;
59
- criticalErrors: string[];
60
- commonErrors: string[];
61
- executionTime: number;
62
- }
63
-
64
- /**
65
- * GitHub API client for fetching workflow data
66
- */
67
- export class GitHubWorkflowDebugger {
68
- private token: string;
69
- private owner: string;
70
- private repo: string;
71
- private apiBase = 'https://api.github.com';
72
-
73
- constructor(token: string, owner: string, repo: string) {
74
- this.token = token;
75
- this.owner = owner;
76
- this.repo = repo;
77
- }
78
-
79
- /**
80
- * Make authenticated GitHub API request
81
- */
82
- private async apiRequest(endpoint: string, method: string = 'GET'): Promise<any> {
83
- const url = `${this.apiBase}/repos/${this.owner}/${this.repo}${endpoint}`;
84
-
85
- const response = await fetch(url, {
86
- method,
87
- headers: {
88
- 'Authorization': `token ${this.token}`,
89
- 'Accept': 'application/vnd.github.v3+json',
90
- 'User-Agent': 'pipecraft-debugger'
91
- }
92
- });
93
-
94
- if (!response.ok) {
95
- throw new Error(`GitHub API request failed: ${response.status} ${response.statusText}`);
96
- }
97
-
98
- return response.json();
99
- }
100
-
101
- /**
102
- * Get recent workflow runs
103
- */
104
- async getWorkflowRuns(workflowName: string, branch?: string, limit: number = 10): Promise<WorkflowRun[]> {
105
- const endpoint = `/actions/workflows/${workflowName}/runs?per_page=${limit}${branch ? `&branch=${branch}` : ''}`;
106
- const response = await this.apiRequest(endpoint);
107
- return response.workflow_runs;
108
- }
109
-
110
- /**
111
- * Get detailed workflow run information
112
- */
113
- async getWorkflowRun(runId: number): Promise<WorkflowRun> {
114
- return this.apiRequest(`/actions/runs/${runId}`);
115
- }
116
-
117
- /**
118
- * Get jobs for a workflow run
119
- */
120
- async getWorkflowJobs(runId: number): Promise<Job[]> {
121
- const response = await this.apiRequest(`/actions/runs/${runId}/jobs`);
122
- return response.jobs;
123
- }
124
-
125
- /**
126
- * Download job logs
127
- */
128
- async getJobLogs(runId: number, jobId: number): Promise<string> {
129
- const url = `${this.apiBase}/repos/${this.owner}/${this.repo}/actions/runs/${runId}/jobs/${jobId}/logs`;
130
-
131
- const response = await fetch(url, {
132
- headers: {
133
- 'Authorization': `token ${this.token}`,
134
- 'Accept': 'application/vnd.github.v3+json',
135
- 'User-Agent': 'pipecraft-debugger'
136
- }
137
- });
138
-
139
- if (!response.ok) {
140
- throw new Error(`Failed to download logs: ${response.status} ${response.statusText}`);
141
- }
142
-
143
- return response.text();
144
- }
145
- }
146
-
147
- /**
148
- * Analyze workflow failures and generate insights
149
- */
150
- export class WorkflowAnalyzer {
151
- /**
152
- * Analyze a workflow run for failures
153
- */
154
- static analyzeWorkflowRun(run: WorkflowRun, jobs: Job[]): DebugAnalysis {
155
- const failedJobs = jobs.filter(job =>
156
- job.conclusion === 'failure' || job.conclusion === 'cancelled'
157
- );
158
-
159
- const successRate = jobs.length > 0 ?
160
- ((jobs.length - failedJobs.length) / jobs.length) * 100 : 0;
161
-
162
- const commonFailurePatterns = this.extractFailurePatterns(failedJobs);
163
- const recommendations = this.generateRecommendations(failedJobs, commonFailurePatterns);
164
-
165
- return {
166
- runId: run.id,
167
- status: run.status,
168
- conclusion: run.conclusion,
169
- failedJobs,
170
- totalJobs: jobs.length,
171
- successRate,
172
- commonFailurePatterns,
173
- recommendations
174
- };
175
- }
176
-
177
- /**
178
- * Extract common failure patterns from failed jobs
179
- */
180
- private static extractFailurePatterns(failedJobs: Job[]): string[] {
181
- const patterns: string[] = [];
182
- const stepFailures = new Map<string, number>();
183
-
184
- failedJobs.forEach(job => {
185
- job.steps.forEach(step => {
186
- if (step.conclusion === 'failure') {
187
- const pattern = this.categorizeFailure(step.name);
188
- stepFailures.set(pattern, (stepFailures.get(pattern) || 0) + 1);
189
- }
190
- });
191
- });
192
-
193
- // Sort by frequency and return top patterns
194
- return Array.from(stepFailures.entries())
195
- .sort((a, b) => b[1] - a[1])
196
- .slice(0, 5)
197
- .map(([pattern]) => pattern);
198
- }
199
-
200
- /**
201
- * Categorize failure types based on step names
202
- */
203
- private static categorizeFailure(stepName: string): string {
204
- const name = stepName.toLowerCase();
205
-
206
- if (name.includes('test') || name.includes('spec')) return 'Test Failures';
207
- if (name.includes('build') || name.includes('compile')) return 'Build Failures';
208
- if (name.includes('lint') || name.includes('format')) return 'Linting Issues';
209
- if (name.includes('deploy') || name.includes('release')) return 'Deployment Issues';
210
- if (name.includes('install') || name.includes('dependencies')) return 'Dependency Issues';
211
- if (name.includes('docker') || name.includes('container')) return 'Docker Issues';
212
- if (name.includes('security') || name.includes('scan')) return 'Security Issues';
213
-
214
- return 'Other Failures';
215
- }
216
-
217
- /**
218
- * Generate recommendations based on failure analysis
219
- */
220
- private static generateRecommendations(failedJobs: Job[], patterns: string[]): string[] {
221
- const recommendations: string[] = [];
222
-
223
- if (patterns.includes('Test Failures')) {
224
- recommendations.push('Review test cases and ensure they are up to date');
225
- recommendations.push('Check for flaky tests and add retry mechanisms');
226
- }
227
-
228
- if (patterns.includes('Build Failures')) {
229
- recommendations.push('Verify build dependencies and versions');
230
- recommendations.push('Check for breaking changes in dependencies');
231
- }
232
-
233
- if (patterns.includes('Linting Issues')) {
234
- recommendations.push('Run linting locally before pushing');
235
- recommendations.push('Configure pre-commit hooks for automatic linting');
236
- }
237
-
238
- if (patterns.includes('Dependency Issues')) {
239
- recommendations.push('Update package-lock.json or yarn.lock');
240
- recommendations.push('Check for version conflicts in dependencies');
241
- }
242
-
243
- if (patterns.includes('Docker Issues')) {
244
- recommendations.push('Verify Dockerfile syntax and base images');
245
- recommendations.push('Check for resource constraints in CI environment');
246
- }
247
-
248
- if (failedJobs.length > 3) {
249
- recommendations.push('Consider breaking down large workflows into smaller, focused jobs');
250
- }
251
-
252
- return recommendations;
253
- }
254
- }
255
-
256
- /**
257
- * Analyze job logs for patterns and errors
258
- */
259
- export class LogAnalyzer {
260
- /**
261
- * Analyze job logs for errors and patterns
262
- */
263
- static analyzeLogs(logs: string, jobName: string): LogAnalysis {
264
- const lines = logs.split('\n');
265
- const errorCount = lines.filter(line =>
266
- line.toLowerCase().includes('error') ||
267
- line.toLowerCase().includes('failed') ||
268
- line.toLowerCase().includes('exception')
269
- ).length;
270
-
271
- const warningCount = lines.filter(line =>
272
- line.toLowerCase().includes('warning') ||
273
- line.toLowerCase().includes('warn')
274
- ).length;
275
-
276
- const criticalErrors = this.extractCriticalErrors(lines);
277
- const commonErrors = this.extractCommonErrors(lines);
278
- const executionTime = this.calculateExecutionTime(lines);
279
-
280
- return {
281
- jobId: 0, // Will be set by caller
282
- jobName,
283
- errorCount,
284
- warningCount,
285
- criticalErrors,
286
- commonErrors,
287
- executionTime
288
- };
289
- }
290
-
291
- /**
292
- * Extract critical errors from logs
293
- */
294
- private static extractCriticalErrors(lines: string[]): string[] {
295
- const criticalPatterns = [
296
- /fatal error/i,
297
- /segmentation fault/i,
298
- /out of memory/i,
299
- /connection refused/i,
300
- /permission denied/i,
301
- /file not found/i,
302
- /timeout/i
303
- ];
304
-
305
- const errors: string[] = [];
306
- lines.forEach(line => {
307
- criticalPatterns.forEach(pattern => {
308
- if (pattern.test(line)) {
309
- errors.push(line.trim());
310
- }
311
- });
312
- });
313
-
314
- return [...new Set(errors)]; // Remove duplicates
315
- }
316
-
317
- /**
318
- * Extract common error patterns
319
- */
320
- private static extractCommonErrors(lines: string[]): string[] {
321
- const errorMap = new Map<string, number>();
322
-
323
- lines.forEach(line => {
324
- if (line.toLowerCase().includes('error')) {
325
- // Extract error type (first few words after "error")
326
- const match = line.match(/error[:\s]+([^:]+)/i);
327
- if (match) {
328
- const errorType = match[1].trim().split(' ').slice(0, 3).join(' ');
329
- errorMap.set(errorType, (errorMap.get(errorType) || 0) + 1);
330
- }
331
- }
332
- });
333
-
334
- return Array.from(errorMap.entries())
335
- .sort((a, b) => b[1] - a[1])
336
- .slice(0, 5)
337
- .map(([error]) => error);
338
- }
339
-
340
- /**
341
- * Calculate execution time from logs
342
- */
343
- private static calculateExecutionTime(lines: string[]): number {
344
- const timePattern = /(\d+):(\d+):(\d+)/;
345
- const times: number[] = [];
346
-
347
- lines.forEach(line => {
348
- const match = line.match(timePattern);
349
- if (match) {
350
- const [, hours, minutes, seconds] = match;
351
- const totalSeconds = parseInt(hours) * 3600 + parseInt(minutes) * 60 + parseInt(seconds);
352
- times.push(totalSeconds);
353
- }
354
- });
355
-
356
- if (times.length < 2) return 0;
357
-
358
- const start = Math.min(...times);
359
- const end = Math.max(...times);
360
- return end - start;
361
- }
362
- }
363
-
364
- /**
365
- * Generate comprehensive debug reports
366
- */
367
- export class DebugReportGenerator {
368
- /**
369
- * Generate a comprehensive debug report
370
- */
371
- static async generateReport(
372
- analysis: DebugAnalysis,
373
- logAnalyses: LogAnalysis[],
374
- outputDir: string
375
- ): Promise<string> {
376
- const reportPath = join(outputDir, 'debug-report.md');
377
-
378
- if (!existsSync(outputDir)) {
379
- mkdirSync(outputDir, { recursive: true });
380
- }
381
-
382
- const report = this.buildMarkdownReport(analysis, logAnalyses);
383
- writeFileSync(reportPath, report);
384
-
385
- return reportPath;
386
- }
387
-
388
- /**
389
- * Build markdown report content
390
- */
391
- private static buildMarkdownReport(analysis: DebugAnalysis, logAnalyses: LogAnalysis[]): string {
392
- const timestamp = new Date().toISOString();
393
-
394
- return `# GitHub Actions Debug Report
395
-
396
- Generated: ${timestamp}
397
- Workflow Run: ${analysis.runId}
398
- Status: ${analysis.status}
399
- Conclusion: ${analysis.conclusion || 'N/A'}
400
-
401
- ## Summary
402
-
403
- - **Total Jobs**: ${analysis.totalJobs}
404
- - **Failed Jobs**: ${analysis.failedJobs.length}
405
- - **Success Rate**: ${analysis.successRate.toFixed(1)}%
406
-
407
- ## Failed Jobs
408
-
409
- ${analysis.failedJobs.map(job => `
410
- ### ${job.name}
411
- - **Status**: ${job.status}
412
- - **Conclusion**: ${job.conclusion}
413
- - **URL**: ${job.html_url}
414
- - **Duration**: ${this.formatDuration(job.started_at, job.completed_at)}
415
-
416
- #### Failed Steps
417
- ${job.steps.filter(step => step.conclusion === 'failure').map(step => `
418
- - ${step.name} (${step.conclusion})
419
- `).join('')}
420
- `).join('')}
421
-
422
- ## Common Failure Patterns
423
-
424
- ${analysis.commonFailurePatterns.map(pattern => `- ${pattern}`).join('\n')}
425
-
426
- ## Recommendations
427
-
428
- ${analysis.recommendations.map(rec => `- ${rec}`).join('\n')}
429
-
430
- ## Log Analysis
431
-
432
- ${logAnalyses.map(log => `
433
- ### ${log.jobName}
434
- - **Errors**: ${log.errorCount}
435
- - **Warnings**: ${log.warningCount}
436
- - **Execution Time**: ${log.executionTime}s
437
-
438
- #### Critical Errors
439
- ${log.criticalErrors.map(error => `- ${error}`).join('\n')}
440
-
441
- #### Common Errors
442
- ${log.commonErrors.map(error => `- ${error}`).join('\n')}
443
- `).join('')}
444
-
445
- ## Next Steps
446
-
447
- 1. Review failed jobs and their logs
448
- 2. Address common failure patterns
449
- 3. Implement recommended improvements
450
- 4. Test changes locally before pushing
451
- 5. Consider adding more granular job dependencies
452
-
453
- ---
454
- *Report generated by Pipecraft Debug Tools*
455
- `;
456
- }
457
-
458
- /**
459
- * Format duration between two timestamps
460
- */
461
- private static formatDuration(start: string, end: string | null): string {
462
- if (!end) return 'In progress';
463
-
464
- const startTime = new Date(start).getTime();
465
- const endTime = new Date(end).getTime();
466
- const durationMs = endTime - startTime;
467
-
468
- const minutes = Math.floor(durationMs / 60000);
469
- const seconds = Math.floor((durationMs % 60000) / 1000);
470
-
471
- return `${minutes}m ${seconds}s`;
472
- }
473
- }
474
-
475
- /**
476
- * Main debugging orchestrator
477
- */
478
- export class WorkflowDebugOrchestrator {
479
- private debugger: GitHubWorkflowDebugger;
480
- private outputDir: string;
481
-
482
- constructor(token: string, owner: string, repo: string, outputDir: string = './debug-output') {
483
- this.debugger = new GitHubWorkflowDebugger(token, owner, repo);
484
- this.outputDir = outputDir;
485
- }
486
-
487
- /**
488
- * Run comprehensive workflow debugging
489
- */
490
- async debugWorkflow(workflowName: string, branch?: string, limit: number = 10): Promise<string> {
491
- console.log(`🔍 Debugging workflow: ${workflowName}`);
492
-
493
- // Get recent runs
494
- const runs = await this.debugger.getWorkflowRuns(workflowName, branch, limit);
495
-
496
- if (runs.length === 0) {
497
- throw new Error('No workflow runs found');
498
- }
499
-
500
- // Find failed runs
501
- const failedRuns = runs.filter(run =>
502
- run.conclusion === 'failure' || run.conclusion === 'cancelled'
503
- );
504
-
505
- if (failedRuns.length === 0) {
506
- console.log('✅ No failed runs found');
507
- return '';
508
- }
509
-
510
- console.log(`📊 Found ${failedRuns.length} failed runs`);
511
-
512
- // Analyze the most recent failed run
513
- const latestFailedRun = failedRuns[0];
514
- const jobs = await this.debugger.getWorkflowJobs(latestFailedRun.id);
515
-
516
- // Perform analysis
517
- const analysis = WorkflowAnalyzer.analyzeWorkflowRun(latestFailedRun, jobs);
518
-
519
- // Analyze logs for failed jobs
520
- const logAnalyses: LogAnalysis[] = [];
521
- for (const job of analysis.failedJobs) {
522
- try {
523
- const logs = await this.debugger.getJobLogs(latestFailedRun.id, job.id);
524
- const logAnalysis = LogAnalyzer.analyzeLogs(logs, job.name);
525
- logAnalysis.jobId = job.id;
526
- logAnalyses.push(logAnalysis);
527
- } catch (error) {
528
- console.warn(`⚠️ Could not fetch logs for job ${job.name}: ${error}`);
529
- }
530
- }
531
-
532
- // Generate report
533
- const reportPath = await DebugReportGenerator.generateReport(analysis, logAnalyses, this.outputDir);
534
-
535
- console.log(`📄 Debug report generated: ${reportPath}`);
536
- return reportPath;
537
- }
538
- }