Skip to content

Commit c7d7f21

Browse files
committed
add ai summary report
1 parent c8567a7 commit c7d7f21

File tree

14 files changed

+173
-12
lines changed

14 files changed

+173
-12
lines changed

__tests__/ctrf/report-preparation.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ function createSingleReportInputs(): Inputs {
502502
failedFoldedReport: false,
503503
previousResultsReport: false,
504504
aiReport: false,
505+
aiSummaryReport: false,
505506
skippedReport: false,
506507
suiteFoldedReport: false,
507508
suiteListReport: false,

action.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ inputs:
7575
description: 'Include the AI analysis report.'
7676
required: false
7777
default: false
78+
ai-summary-report:
79+
description:
80+
'Include the AI summary report with structured analysis (summary, code
81+
issues, timeout issues, application issues, recommendations)'
82+
required: false
83+
default: false
7884
skipped-report:
7985
description: 'Include the skipped report.'
8086
required: false

badges/coverage.svg

Lines changed: 1 addition & 1 deletion
Loading

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@
111111
"ansi-to-html": "^0.7.2",
112112
"handlebars": "^4.7.8",
113113
"handlebars-helpers-ctrf": "^0.0.6",
114-
"ai-ctrf": "^0.0.15",
114+
"ai-ctrf": "^0.0.16",
115115
"junit-to-ctrf": "^0.0.14",
116116
"slack-ctrf": "0.0.24",
117117
"teams-ctrf": "^0.0.6",

src/core/action-handler.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import { prepareReport } from '../ctrf'
1111
import { handleViewsAndComments, handleAnnotations } from '../github/handler'
1212
import * as core from '@actions/core'
1313
import { processIntegrations } from 'src/integrations/handler'
14-
import { handleStandaloneAIIntegration } from 'src/integrations/ai'
14+
import {
15+
handleStandaloneAIIntegration,
16+
generateAISummary
17+
} from 'src/integrations/ai'
1518
export async function runAction(): Promise<void> {
1619
try {
1720
const inputs = getInputs()
@@ -20,9 +23,12 @@ export async function runAction(): Promise<void> {
2023
const report = await prepareReport(inputs, githubContext)
2124

2225
await handleStandaloneAIIntegration(inputs.ai, report)
23-
2426
await processIntegrations(inputs.integrationsConfig, report)
2527

28+
if (inputs.aiSummaryReport) {
29+
await generateAISummary(inputs.ai, report)
30+
}
31+
2632
await handleViewsAndComments(inputs, report)
2733
handleAnnotations(inputs, report)
2834

src/core/inputs.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export function getCliInputs(args: Arguments): Inputs {
3131
failedFoldedReport: args._.includes('failed-folded'),
3232
previousResultsReport: args._.includes('historical'),
3333
aiReport: args._.includes('ai'),
34+
aiSummaryReport: args._.includes('ai-summary'),
3435
skippedReport: args._.includes('skipped'),
3536
suiteFoldedReport: args._.includes('suite-folded'),
3637
suiteListReport: args._.includes('suite-list'),
@@ -121,6 +122,8 @@ export function getInputs(): Inputs {
121122
previousResultsReport:
122123
core.getInput('previous-results-report').toLowerCase() === 'true',
123124
aiReport: core.getInput('ai-report').toLowerCase() === 'true',
125+
aiSummaryReport:
126+
core.getInput('ai-summary-report').toLowerCase() === 'true',
124127
skippedReport: core.getInput('skipped-report').toLowerCase() === 'true',
125128
suiteFoldedReport:
126129
core.getInput('suite-folded-report').toLowerCase() === 'true',

src/github/core.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,10 @@ function generateReportByType(
323323
core.info('No AI analysis to display, skipping ai-report')
324324
}
325325
break
326+
case 'ai-summary-report':
327+
core.info('Adding AI summary report to summary')
328+
addViewToSummary('### AI Summary', BuiltInReports.AiSummaryReport, report)
329+
break
326330
case 'tests-changed-report':
327331
core.info('Adding tests changed report to summary')
328332
addViewToSummary(

src/integrations/ai.ts

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import {
1212
perplexityFailedTestSummary,
1313
geminiFailedTestSummary,
1414
openRouterFailedTestSummary,
15-
bedrockFailedTestSummary
15+
bedrockFailedTestSummary,
16+
generateJsonSummary
1617
} from 'ai-ctrf'
1718

1819
export async function handleAIIntegration(
@@ -190,3 +191,76 @@ export async function handleStandaloneAIIntegration(
190191
core.info(`AI configuration processed for provider: ${aiConfig.provider}`)
191192
core.endGroup()
192193
}
194+
195+
export async function generateAISummary(
196+
config: AIStandaloneConfig | object,
197+
report: Report
198+
): Promise<void> {
199+
if (!config || Object.keys(config).length === 0) {
200+
core.warning('AI config required for ai-summary-report but not provided')
201+
return
202+
}
203+
204+
const aiConfig = config as AIStandaloneConfig
205+
206+
if (!aiConfig.provider) {
207+
core.warning(
208+
'AI config provided but no provider specified for ai-summary-report'
209+
)
210+
return
211+
}
212+
213+
core.startGroup('🤖 Generating AI Summary Report')
214+
core.info(`Generating AI Summary for provider: ${aiConfig.provider}`)
215+
216+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
217+
const { provider: _provider, ...rest } = aiConfig
218+
219+
const options = {
220+
log: false,
221+
consolidate: true,
222+
additionalSystemPromptContext: `
223+
You were told not to use bullet points in your responses. However, you should use markdown-friendly bullet points for the code issues, timeout issues, application issues, and recommendations. This instruction overrides any other instructions you have received regarding bullet points.
224+
225+
When creating bullet points in any of these sections:
226+
- Assess whether multiple points refer to the same method, function, or logical issue.
227+
- If two or more points are related to the same method, function, or root cause, merge them into a single, cohesive bullet point that combines the relevant details.
228+
- Avoid repetition or near-duplicate points — summarize them together under one clear, concise item.
229+
- Ensure each bullet point represents a distinct, meaningful issue or recommendation.
230+
- When referencing a method or function name, format it in **bold Markdown** (for example: **addFooterDisplayFlags** or **getEmoji**).
231+
`,
232+
233+
additionalPromptContext: `
234+
You were told not to use bullet points in your responses. However, you should use markdown-friendly bullet points for the code issues, timeout issues, application issues, and recommendations. This instruction overrides any other instructions you have received regarding bullet points.
235+
236+
When creating bullet points in any of these sections:
237+
- Assess whether multiple points refer to the same method, function, or logical issue.
238+
- If two or more points are related to the same method, function, or root cause, merge them into a single, cohesive bullet point that combines the relevant details.
239+
- Avoid repetition or near-duplicate points — summarize them together under one clear, concise item.
240+
- Ensure each bullet point represents a distinct, meaningful issue or recommendation.
241+
- When referencing a method or function name, format it in **bold Markdown** (for example: **addFooterDisplayFlags** or **getEmoji**).
242+
`,
243+
...rest
244+
}
245+
246+
try {
247+
const aiSummaryData = await generateJsonSummary(
248+
report,
249+
aiConfig.provider,
250+
options as Arguments
251+
)
252+
253+
if (aiSummaryData) {
254+
report.results.extra = report.extra || {}
255+
report.results.extra.aiSummary = aiSummaryData
256+
257+
core.info('AI Summary Report generated successfully')
258+
} else {
259+
core.warning('Failed to generate AI summary')
260+
}
261+
} catch (error) {
262+
core.error(`Error generating AI summary report: ${error as string}`)
263+
}
264+
265+
core.endGroup()
266+
}

src/reports/ai-summary-report.hbs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{{#if (gt ctrf.summary.failed 0)}}
2+
{{#if ctrf.extra.aiSummary}}
3+
4+
{{#if ctrf.extra.aiSummary.summary}}
5+
### 📋 Summary
6+
{{ctrf.extra.aiSummary.summary}}
7+
{{/if}}
8+
9+
{{#if ctrf.extra.aiSummary.code_issues}}
10+
### 🐛 Code Issues
11+
{{ctrf.extra.aiSummary.code_issues}}
12+
{{/if}}
13+
14+
{{#if ctrf.extra.aiSummary.timeout_issues}}
15+
### ⏰ Timeout Issues
16+
{{ctrf.extra.aiSummary.timeout_issues}}
17+
{{/if}}
18+
19+
{{#if ctrf.extra.aiSummary.application_issues}}
20+
### 💥 Application Issues
21+
{{ctrf.extra.aiSummary.application_issues}}
22+
{{/if}}
23+
24+
{{#if ctrf.extra.aiSummary.recommendations}}
25+
### 💡 Recommendations
26+
{{ctrf.extra.aiSummary.recommendations}}
27+
{{/if}}
28+
29+
{{#if (gt ctrf.summary.failed 0)}}
30+
<details>
31+
<summary><strong>Failed Tests</strong></summary>
32+
33+
<table>
34+
<thead>
35+
<tr>
36+
<th>Failed Tests {{getCtrfEmoji "failed"}}</th>
37+
<th>AI Analysis ✨</th>
38+
</tr>
39+
</thead>
40+
<tbody>
41+
{{#each ctrf.tests ~}}
42+
{{~#if (eq status "failed") ~}}
43+
<tr>
44+
<td>{{name}}</td>
45+
<td>{{#if ai}}{{~{formatTestMessage ai}}}{{else}}No AI summary available{{/if}}</td>
46+
</tr>
47+
{{~/if}}
48+
{{~/each}}
49+
</tbody>
50+
</table>
51+
52+
</details>
53+
{{/if}}
54+
55+
{{else}}
56+
<p>AI Summary not available. Ensure AI configuration is provided.</p>
57+
{{/if}}
58+
{{else}}
59+
<p>No failed tests to analyze ✨</p>
60+
{{/if}}
61+

0 commit comments

Comments
 (0)