qualyx 0.3.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.
- package/LICENSE +21 -0
- package/README.md +523 -0
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +124 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/list.d.ts +3 -0
- package/dist/cli/commands/list.d.ts.map +1 -0
- package/dist/cli/commands/list.js +122 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/run.d.ts +12 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +160 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/schedule.d.ts +19 -0
- package/dist/cli/commands/schedule.d.ts.map +1 -0
- package/dist/cli/commands/schedule.js +240 -0
- package/dist/cli/commands/schedule.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +3 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +47 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +194 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/claude-runner.d.ts +23 -0
- package/dist/core/claude-runner.d.ts.map +1 -0
- package/dist/core/claude-runner.js +196 -0
- package/dist/core/claude-runner.js.map +1 -0
- package/dist/core/config-loader.d.ts +137 -0
- package/dist/core/config-loader.d.ts.map +1 -0
- package/dist/core/config-loader.js +239 -0
- package/dist/core/config-loader.js.map +1 -0
- package/dist/core/executor.d.ts +75 -0
- package/dist/core/executor.d.ts.map +1 -0
- package/dist/core/executor.js +337 -0
- package/dist/core/executor.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +7 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/prompt-builder.d.ts +24 -0
- package/dist/core/prompt-builder.d.ts.map +1 -0
- package/dist/core/prompt-builder.js +145 -0
- package/dist/core/prompt-builder.js.map +1 -0
- package/dist/core/retry-handler.d.ts +42 -0
- package/dist/core/retry-handler.d.ts.map +1 -0
- package/dist/core/retry-handler.js +126 -0
- package/dist/core/retry-handler.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/email.d.ts +38 -0
- package/dist/integrations/email.d.ts.map +1 -0
- package/dist/integrations/email.js +216 -0
- package/dist/integrations/email.js.map +1 -0
- package/dist/integrations/index.d.ts +5 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +5 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/jira.d.ts +68 -0
- package/dist/integrations/jira.d.ts.map +1 -0
- package/dist/integrations/jira.js +288 -0
- package/dist/integrations/jira.js.map +1 -0
- package/dist/integrations/slack.d.ts +66 -0
- package/dist/integrations/slack.d.ts.map +1 -0
- package/dist/integrations/slack.js +192 -0
- package/dist/integrations/slack.js.map +1 -0
- package/dist/integrations/teams.d.ts +72 -0
- package/dist/integrations/teams.d.ts.map +1 -0
- package/dist/integrations/teams.js +197 -0
- package/dist/integrations/teams.js.map +1 -0
- package/dist/reporters/console.d.ts +83 -0
- package/dist/reporters/console.d.ts.map +1 -0
- package/dist/reporters/console.js +299 -0
- package/dist/reporters/console.js.map +1 -0
- package/dist/reporters/html.d.ts +29 -0
- package/dist/reporters/html.d.ts.map +1 -0
- package/dist/reporters/html.js +105 -0
- package/dist/reporters/html.js.map +1 -0
- package/dist/storage/results.d.ts +61 -0
- package/dist/storage/results.d.ts.map +1 -0
- package/dist/storage/results.js +111 -0
- package/dist/storage/results.js.map +1 -0
- package/dist/storage/sqlite.d.ts +70 -0
- package/dist/storage/sqlite.d.ts.map +1 -0
- package/dist/storage/sqlite.js +240 -0
- package/dist/storage/sqlite.js.map +1 -0
- package/dist/types/index.d.ts +1239 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +105 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +75 -0
- package/templates/crontab.hbs +24 -0
- package/templates/github-schedule.yml.hbs +153 -0
- package/templates/prompt.md.hbs +147 -0
- package/templates/report.html.hbs +423 -0
- package/templates/slack-message.json.hbs +93 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { RunResult, SlackConfig, QualyxConfig } from '../types/index.js';
|
|
2
|
+
export interface SlackMessage {
|
|
3
|
+
text: string;
|
|
4
|
+
blocks?: SlackBlock[];
|
|
5
|
+
attachments?: SlackAttachment[];
|
|
6
|
+
}
|
|
7
|
+
interface SlackBlock {
|
|
8
|
+
type: string;
|
|
9
|
+
text?: {
|
|
10
|
+
type: string;
|
|
11
|
+
text: string;
|
|
12
|
+
emoji?: boolean;
|
|
13
|
+
};
|
|
14
|
+
fields?: Array<{
|
|
15
|
+
type: string;
|
|
16
|
+
text: string;
|
|
17
|
+
}>;
|
|
18
|
+
elements?: Array<{
|
|
19
|
+
type: string;
|
|
20
|
+
text?: string | {
|
|
21
|
+
type: string;
|
|
22
|
+
text: string;
|
|
23
|
+
};
|
|
24
|
+
url?: string;
|
|
25
|
+
action_id?: string;
|
|
26
|
+
}>;
|
|
27
|
+
accessory?: {
|
|
28
|
+
type: string;
|
|
29
|
+
text?: {
|
|
30
|
+
type: string;
|
|
31
|
+
text: string;
|
|
32
|
+
emoji?: boolean;
|
|
33
|
+
};
|
|
34
|
+
url?: string;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
interface SlackAttachment {
|
|
38
|
+
color: string;
|
|
39
|
+
blocks?: SlackBlock[];
|
|
40
|
+
fallback?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Slack notification integration for Qualyx test results.
|
|
44
|
+
*/
|
|
45
|
+
export declare class SlackNotifier {
|
|
46
|
+
private config;
|
|
47
|
+
constructor(config: SlackConfig);
|
|
48
|
+
/**
|
|
49
|
+
* Determine if a notification should be sent based on run result.
|
|
50
|
+
*/
|
|
51
|
+
shouldNotify(runResult: RunResult): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Build the Slack message payload.
|
|
54
|
+
*/
|
|
55
|
+
buildMessage(runResult: RunResult, organizationName: string, reportUrl?: string): SlackMessage;
|
|
56
|
+
/**
|
|
57
|
+
* Send notification to Slack.
|
|
58
|
+
*/
|
|
59
|
+
send(runResult: RunResult, organizationName: string, reportUrl?: string): Promise<void>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Send a Slack notification for a test run.
|
|
63
|
+
*/
|
|
64
|
+
export declare function sendSlackNotification(runResult: RunResult, config: QualyxConfig, reportUrl?: string): Promise<void>;
|
|
65
|
+
export {};
|
|
66
|
+
//# sourceMappingURL=slack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../src/integrations/slack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE9E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;CACjC;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;IACF,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,GAAG;YACd,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;SACd,CAAC;QACF,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;IACH,SAAS,CAAC,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE;YACL,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,CAAC,EAAE,OAAO,CAAC;SACjB,CAAC;QACF,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;gBAEhB,MAAM,EAAE,WAAW;IAI/B;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO;IAc3C;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY;IAiI9F;;OAEG;IACG,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAoB9F;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,YAAY,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CASf"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack notification integration for Qualyx test results.
|
|
3
|
+
*/
|
|
4
|
+
export class SlackNotifier {
|
|
5
|
+
config;
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.config = config;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Determine if a notification should be sent based on run result.
|
|
11
|
+
*/
|
|
12
|
+
shouldNotify(runResult) {
|
|
13
|
+
const hasFailed = runResult.failed > 0;
|
|
14
|
+
if (hasFailed && this.config.on_failure) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (!hasFailed && this.config.on_success) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build the Slack message payload.
|
|
24
|
+
*/
|
|
25
|
+
buildMessage(runResult, organizationName, reportUrl) {
|
|
26
|
+
const hasFailed = runResult.failed > 0;
|
|
27
|
+
const statusEmoji = hasFailed ? ':x:' : ':white_check_mark:';
|
|
28
|
+
const statusText = hasFailed ? 'FAILED' : 'PASSED';
|
|
29
|
+
const color = hasFailed ? '#e74c3c' : '#2ecc71';
|
|
30
|
+
const passRate = runResult.totalTests > 0
|
|
31
|
+
? Math.round((runResult.passed / runResult.totalTests) * 100)
|
|
32
|
+
: 0;
|
|
33
|
+
// Build mention string for failures
|
|
34
|
+
let mentionText = '';
|
|
35
|
+
if (hasFailed && this.config.mention_on_failure?.length) {
|
|
36
|
+
mentionText = this.config.mention_on_failure.map(id => `<@${id}>`).join(' ') + ' ';
|
|
37
|
+
}
|
|
38
|
+
const blocks = [
|
|
39
|
+
{
|
|
40
|
+
type: 'header',
|
|
41
|
+
text: {
|
|
42
|
+
type: 'plain_text',
|
|
43
|
+
text: `${statusEmoji} Qualyx Test Run ${statusText}`,
|
|
44
|
+
emoji: true,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: 'section',
|
|
49
|
+
fields: [
|
|
50
|
+
{
|
|
51
|
+
type: 'mrkdwn',
|
|
52
|
+
text: `*Organization:*\n${organizationName}`,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: 'mrkdwn',
|
|
56
|
+
text: `*Environment:*\n${runResult.environment}`,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'mrkdwn',
|
|
60
|
+
text: `*Total Tests:*\n${runResult.totalTests}`,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
type: 'mrkdwn',
|
|
64
|
+
text: `*Pass Rate:*\n${passRate}%`,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
type: 'section',
|
|
70
|
+
fields: [
|
|
71
|
+
{
|
|
72
|
+
type: 'mrkdwn',
|
|
73
|
+
text: `:white_check_mark: *Passed:* ${runResult.passed}`,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: 'mrkdwn',
|
|
77
|
+
text: `:x: *Failed:* ${runResult.failed}`,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
type: 'mrkdwn',
|
|
81
|
+
text: `:arrow_right: *Skipped:* ${runResult.skipped}`,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
type: 'mrkdwn',
|
|
85
|
+
text: `:clock1: *Duration:* ${formatDuration(runResult.duration)}`,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
// Add failed tests details
|
|
91
|
+
if (hasFailed) {
|
|
92
|
+
const failedTests = runResult.results.filter(r => r.status === 'failed');
|
|
93
|
+
const failedTestsList = failedTests
|
|
94
|
+
.slice(0, 5) // Limit to 5 failures
|
|
95
|
+
.map(t => `• *${t.ruleName}* (${t.appName}): ${t.error || 'Unknown error'}`)
|
|
96
|
+
.join('\n');
|
|
97
|
+
blocks.push({
|
|
98
|
+
type: 'section',
|
|
99
|
+
text: {
|
|
100
|
+
type: 'mrkdwn',
|
|
101
|
+
text: `*Failed Tests:*\n${failedTestsList}${failedTests.length > 5 ? `\n_...and ${failedTests.length - 5} more_` : ''}`,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
// Add report link if available
|
|
106
|
+
if (reportUrl) {
|
|
107
|
+
blocks.push({
|
|
108
|
+
type: 'section',
|
|
109
|
+
text: {
|
|
110
|
+
type: 'mrkdwn',
|
|
111
|
+
text: ':page_facing_up: *View Full Report:*',
|
|
112
|
+
},
|
|
113
|
+
accessory: {
|
|
114
|
+
type: 'button',
|
|
115
|
+
text: {
|
|
116
|
+
type: 'plain_text',
|
|
117
|
+
text: 'Open Report',
|
|
118
|
+
emoji: true,
|
|
119
|
+
},
|
|
120
|
+
url: reportUrl,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
// Add context with run ID and timestamp
|
|
125
|
+
blocks.push({
|
|
126
|
+
type: 'context',
|
|
127
|
+
elements: [
|
|
128
|
+
{
|
|
129
|
+
type: 'mrkdwn',
|
|
130
|
+
text: `Run ID: ${runResult.runId.slice(0, 8)}... | ${new Date(runResult.startedAt).toLocaleString()}`,
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
});
|
|
134
|
+
return {
|
|
135
|
+
text: `${mentionText}Qualyx Test Run ${statusText}: ${runResult.passed}/${runResult.totalTests} passed`,
|
|
136
|
+
blocks,
|
|
137
|
+
attachments: [
|
|
138
|
+
{
|
|
139
|
+
color,
|
|
140
|
+
fallback: `Test run ${statusText}: ${runResult.passed}/${runResult.totalTests} passed`,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Send notification to Slack.
|
|
147
|
+
*/
|
|
148
|
+
async send(runResult, organizationName, reportUrl) {
|
|
149
|
+
if (!this.shouldNotify(runResult)) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const message = this.buildMessage(runResult, organizationName, reportUrl);
|
|
153
|
+
const response = await fetch(this.config.webhook_url, {
|
|
154
|
+
method: 'POST',
|
|
155
|
+
headers: {
|
|
156
|
+
'Content-Type': 'application/json',
|
|
157
|
+
},
|
|
158
|
+
body: JSON.stringify(message),
|
|
159
|
+
});
|
|
160
|
+
if (!response.ok) {
|
|
161
|
+
const errorText = await response.text();
|
|
162
|
+
throw new Error(`Slack notification failed: ${response.status} ${errorText}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Send a Slack notification for a test run.
|
|
168
|
+
*/
|
|
169
|
+
export async function sendSlackNotification(runResult, config, reportUrl) {
|
|
170
|
+
const slackConfig = config.notifications?.slack;
|
|
171
|
+
if (!slackConfig) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const notifier = new SlackNotifier(slackConfig);
|
|
175
|
+
await notifier.send(runResult, config.organization.name, reportUrl);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Format duration in human-readable format.
|
|
179
|
+
*/
|
|
180
|
+
function formatDuration(ms) {
|
|
181
|
+
if (ms < 1000) {
|
|
182
|
+
return `${ms}ms`;
|
|
183
|
+
}
|
|
184
|
+
const seconds = Math.floor(ms / 1000);
|
|
185
|
+
if (seconds < 60) {
|
|
186
|
+
return `${seconds}s`;
|
|
187
|
+
}
|
|
188
|
+
const minutes = Math.floor(seconds / 60);
|
|
189
|
+
const remainingSeconds = seconds % 60;
|
|
190
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=slack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack.js","sourceRoot":"","sources":["../../src/integrations/slack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { RunResult, TeamsConfig, QualyxConfig } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Microsoft Teams Adaptive Card structure
|
|
4
|
+
*/
|
|
5
|
+
interface AdaptiveCard {
|
|
6
|
+
type: string;
|
|
7
|
+
attachments: Array<{
|
|
8
|
+
contentType: string;
|
|
9
|
+
contentUrl: null;
|
|
10
|
+
content: {
|
|
11
|
+
$schema: string;
|
|
12
|
+
type: string;
|
|
13
|
+
version: string;
|
|
14
|
+
body: Array<{
|
|
15
|
+
type: string;
|
|
16
|
+
text?: string;
|
|
17
|
+
size?: string;
|
|
18
|
+
weight?: string;
|
|
19
|
+
color?: string;
|
|
20
|
+
wrap?: boolean;
|
|
21
|
+
columns?: Array<{
|
|
22
|
+
type: string;
|
|
23
|
+
width: string;
|
|
24
|
+
items: Array<{
|
|
25
|
+
type: string;
|
|
26
|
+
text: string;
|
|
27
|
+
size?: string;
|
|
28
|
+
weight?: string;
|
|
29
|
+
color?: string;
|
|
30
|
+
horizontalAlignment?: string;
|
|
31
|
+
}>;
|
|
32
|
+
}>;
|
|
33
|
+
facts?: Array<{
|
|
34
|
+
title: string;
|
|
35
|
+
value: string;
|
|
36
|
+
}>;
|
|
37
|
+
style?: string;
|
|
38
|
+
bleed?: boolean;
|
|
39
|
+
}>;
|
|
40
|
+
actions?: Array<{
|
|
41
|
+
type: string;
|
|
42
|
+
title: string;
|
|
43
|
+
url: string;
|
|
44
|
+
}>;
|
|
45
|
+
};
|
|
46
|
+
}>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Microsoft Teams notification integration for Qualyx test results.
|
|
50
|
+
*/
|
|
51
|
+
export declare class TeamsNotifier {
|
|
52
|
+
private config;
|
|
53
|
+
constructor(config: TeamsConfig);
|
|
54
|
+
/**
|
|
55
|
+
* Determine if a notification should be sent based on run result.
|
|
56
|
+
*/
|
|
57
|
+
shouldNotify(runResult: RunResult): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Build the Teams Adaptive Card message.
|
|
60
|
+
*/
|
|
61
|
+
buildMessage(runResult: RunResult, organizationName: string, reportUrl?: string): AdaptiveCard;
|
|
62
|
+
/**
|
|
63
|
+
* Send notification to Microsoft Teams.
|
|
64
|
+
*/
|
|
65
|
+
send(runResult: RunResult, organizationName: string, reportUrl?: string): Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Send a Teams notification for a test run.
|
|
69
|
+
*/
|
|
70
|
+
export declare function sendTeamsNotification(runResult: RunResult, config: QualyxConfig, reportUrl?: string): Promise<void>;
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=teams.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teams.d.ts","sourceRoot":"","sources":["../../src/integrations/teams.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE9E;;GAEG;AACH,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,KAAK,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,IAAI,CAAC;QACjB,OAAO,EAAE;YACP,OAAO,EAAE,MAAM,CAAC;YAChB,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;YAChB,IAAI,EAAE,KAAK,CAAC;gBACV,IAAI,EAAE,MAAM,CAAC;gBACb,IAAI,CAAC,EAAE,MAAM,CAAC;gBACd,IAAI,CAAC,EAAE,MAAM,CAAC;gBACd,MAAM,CAAC,EAAE,MAAM,CAAC;gBAChB,KAAK,CAAC,EAAE,MAAM,CAAC;gBACf,IAAI,CAAC,EAAE,OAAO,CAAC;gBACf,OAAO,CAAC,EAAE,KAAK,CAAC;oBACd,IAAI,EAAE,MAAM,CAAC;oBACb,KAAK,EAAE,MAAM,CAAC;oBACd,KAAK,EAAE,KAAK,CAAC;wBACX,IAAI,EAAE,MAAM,CAAC;wBACb,IAAI,EAAE,MAAM,CAAC;wBACb,IAAI,CAAC,EAAE,MAAM,CAAC;wBACd,MAAM,CAAC,EAAE,MAAM,CAAC;wBAChB,KAAK,CAAC,EAAE,MAAM,CAAC;wBACf,mBAAmB,CAAC,EAAE,MAAM,CAAC;qBAC9B,CAAC,CAAC;iBACJ,CAAC,CAAC;gBACH,KAAK,CAAC,EAAE,KAAK,CAAC;oBACZ,KAAK,EAAE,MAAM,CAAC;oBACd,KAAK,EAAE,MAAM,CAAC;iBACf,CAAC,CAAC;gBACH,KAAK,CAAC,EAAE,MAAM,CAAC;gBACf,KAAK,CAAC,EAAE,OAAO,CAAC;aACjB,CAAC,CAAC;YACH,OAAO,CAAC,EAAE,KAAK,CAAC;gBACd,IAAI,EAAE,MAAM,CAAC;gBACb,KAAK,EAAE,MAAM,CAAC;gBACd,GAAG,EAAE,MAAM,CAAC;aACb,CAAC,CAAC;SACJ,CAAC;KACH,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;gBAEhB,MAAM,EAAE,WAAW;IAI/B;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO;IAc3C;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY;IAuI9F;;OAEG;IACG,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAoB9F;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,YAAY,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CASf"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Microsoft Teams notification integration for Qualyx test results.
|
|
3
|
+
*/
|
|
4
|
+
export class TeamsNotifier {
|
|
5
|
+
config;
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.config = config;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Determine if a notification should be sent based on run result.
|
|
11
|
+
*/
|
|
12
|
+
shouldNotify(runResult) {
|
|
13
|
+
const hasFailed = runResult.failed > 0;
|
|
14
|
+
if (hasFailed && this.config.on_failure) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (!hasFailed && this.config.on_success) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build the Teams Adaptive Card message.
|
|
24
|
+
*/
|
|
25
|
+
buildMessage(runResult, organizationName, reportUrl) {
|
|
26
|
+
const hasFailed = runResult.failed > 0;
|
|
27
|
+
const statusText = hasFailed ? 'FAILED' : 'PASSED';
|
|
28
|
+
const statusColor = hasFailed ? 'attention' : 'good';
|
|
29
|
+
const passRate = runResult.totalTests > 0
|
|
30
|
+
? Math.round((runResult.passed / runResult.totalTests) * 100)
|
|
31
|
+
: 0;
|
|
32
|
+
const failedTests = runResult.results.filter(r => r.status === 'failed');
|
|
33
|
+
// Build mentions text if configured
|
|
34
|
+
let mentionText = '';
|
|
35
|
+
if (hasFailed && this.config.mention_on_failure?.length) {
|
|
36
|
+
mentionText = this.config.mention_on_failure.map(email => `@${email}`).join(' ') + ' ';
|
|
37
|
+
}
|
|
38
|
+
const body = [
|
|
39
|
+
{
|
|
40
|
+
type: 'TextBlock',
|
|
41
|
+
text: `${mentionText}Qualyx Test Run ${statusText}`,
|
|
42
|
+
size: 'Large',
|
|
43
|
+
weight: 'Bolder',
|
|
44
|
+
color: statusColor,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
type: 'TextBlock',
|
|
48
|
+
text: `${organizationName} - ${runResult.environment}`,
|
|
49
|
+
size: 'Medium',
|
|
50
|
+
color: 'default',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: 'ColumnSet',
|
|
54
|
+
columns: [
|
|
55
|
+
{
|
|
56
|
+
type: 'Column',
|
|
57
|
+
width: 'stretch',
|
|
58
|
+
items: [
|
|
59
|
+
{ type: 'TextBlock', text: 'Total', size: 'Small', weight: 'Bolder', horizontalAlignment: 'Center' },
|
|
60
|
+
{ type: 'TextBlock', text: String(runResult.totalTests), size: 'ExtraLarge', weight: 'Bolder', horizontalAlignment: 'Center' },
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
type: 'Column',
|
|
65
|
+
width: 'stretch',
|
|
66
|
+
items: [
|
|
67
|
+
{ type: 'TextBlock', text: 'Passed', size: 'Small', weight: 'Bolder', color: 'good', horizontalAlignment: 'Center' },
|
|
68
|
+
{ type: 'TextBlock', text: String(runResult.passed), size: 'ExtraLarge', weight: 'Bolder', color: 'good', horizontalAlignment: 'Center' },
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
type: 'Column',
|
|
73
|
+
width: 'stretch',
|
|
74
|
+
items: [
|
|
75
|
+
{ type: 'TextBlock', text: 'Failed', size: 'Small', weight: 'Bolder', color: 'attention', horizontalAlignment: 'Center' },
|
|
76
|
+
{ type: 'TextBlock', text: String(runResult.failed), size: 'ExtraLarge', weight: 'Bolder', color: 'attention', horizontalAlignment: 'Center' },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
type: 'Column',
|
|
81
|
+
width: 'stretch',
|
|
82
|
+
items: [
|
|
83
|
+
{ type: 'TextBlock', text: 'Pass Rate', size: 'Small', weight: 'Bolder', horizontalAlignment: 'Center' },
|
|
84
|
+
{ type: 'TextBlock', text: `${passRate}%`, size: 'ExtraLarge', weight: 'Bolder', horizontalAlignment: 'Center' },
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
// Add failed tests if any
|
|
91
|
+
if (failedTests.length > 0) {
|
|
92
|
+
body.push({
|
|
93
|
+
type: 'TextBlock',
|
|
94
|
+
text: 'Failed Tests',
|
|
95
|
+
size: 'Medium',
|
|
96
|
+
weight: 'Bolder',
|
|
97
|
+
color: 'attention',
|
|
98
|
+
});
|
|
99
|
+
body.push({
|
|
100
|
+
type: 'FactSet',
|
|
101
|
+
facts: failedTests.slice(0, 5).map(t => ({
|
|
102
|
+
title: `${t.ruleName} (${t.appName})`,
|
|
103
|
+
value: t.error || 'Unknown error',
|
|
104
|
+
})),
|
|
105
|
+
});
|
|
106
|
+
if (failedTests.length > 5) {
|
|
107
|
+
body.push({
|
|
108
|
+
type: 'TextBlock',
|
|
109
|
+
text: `...and ${failedTests.length - 5} more failed tests`,
|
|
110
|
+
size: 'Small',
|
|
111
|
+
color: 'default',
|
|
112
|
+
wrap: true,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Add run details
|
|
117
|
+
body.push({
|
|
118
|
+
type: 'FactSet',
|
|
119
|
+
facts: [
|
|
120
|
+
{ title: 'Duration', value: formatDuration(runResult.duration) },
|
|
121
|
+
{ title: 'Run ID', value: runResult.runId.slice(0, 8) + '...' },
|
|
122
|
+
{ title: 'Started', value: new Date(runResult.startedAt).toLocaleString() },
|
|
123
|
+
],
|
|
124
|
+
});
|
|
125
|
+
const actions = [];
|
|
126
|
+
if (reportUrl) {
|
|
127
|
+
actions.push({
|
|
128
|
+
type: 'Action.OpenUrl',
|
|
129
|
+
title: 'View Full Report',
|
|
130
|
+
url: reportUrl,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
type: 'message',
|
|
135
|
+
attachments: [
|
|
136
|
+
{
|
|
137
|
+
contentType: 'application/vnd.microsoft.card.adaptive',
|
|
138
|
+
contentUrl: null,
|
|
139
|
+
content: {
|
|
140
|
+
$schema: 'http://adaptivecards.io/schemas/adaptive-card.json',
|
|
141
|
+
type: 'AdaptiveCard',
|
|
142
|
+
version: '1.4',
|
|
143
|
+
body,
|
|
144
|
+
actions: actions.length > 0 ? actions : undefined,
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Send notification to Microsoft Teams.
|
|
152
|
+
*/
|
|
153
|
+
async send(runResult, organizationName, reportUrl) {
|
|
154
|
+
if (!this.shouldNotify(runResult)) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const message = this.buildMessage(runResult, organizationName, reportUrl);
|
|
158
|
+
const response = await fetch(this.config.webhook_url, {
|
|
159
|
+
method: 'POST',
|
|
160
|
+
headers: {
|
|
161
|
+
'Content-Type': 'application/json',
|
|
162
|
+
},
|
|
163
|
+
body: JSON.stringify(message),
|
|
164
|
+
});
|
|
165
|
+
if (!response.ok) {
|
|
166
|
+
const errorText = await response.text();
|
|
167
|
+
throw new Error(`Teams notification failed: ${response.status} ${errorText}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Send a Teams notification for a test run.
|
|
173
|
+
*/
|
|
174
|
+
export async function sendTeamsNotification(runResult, config, reportUrl) {
|
|
175
|
+
const teamsConfig = config.notifications?.teams;
|
|
176
|
+
if (!teamsConfig) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const notifier = new TeamsNotifier(teamsConfig);
|
|
180
|
+
await notifier.send(runResult, config.organization.name, reportUrl);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Format duration in human-readable format.
|
|
184
|
+
*/
|
|
185
|
+
function formatDuration(ms) {
|
|
186
|
+
if (ms < 1000) {
|
|
187
|
+
return `${ms}ms`;
|
|
188
|
+
}
|
|
189
|
+
const seconds = Math.floor(ms / 1000);
|
|
190
|
+
if (seconds < 60) {
|
|
191
|
+
return `${seconds}s`;
|
|
192
|
+
}
|
|
193
|
+
const minutes = Math.floor(seconds / 60);
|
|
194
|
+
const remainingSeconds = seconds % 60;
|
|
195
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=teams.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teams.js","sourceRoot":"","sources":["../../src/integrations/teams.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { RunResult } from '../types/index.js';
|
|
2
|
+
import type { ExecutorCallbacks } from '../core/executor.js';
|
|
3
|
+
export interface ConsoleReporterOptions {
|
|
4
|
+
verbose?: boolean;
|
|
5
|
+
showPrompts?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Console reporter that provides colored terminal output.
|
|
9
|
+
*/
|
|
10
|
+
export declare class ConsoleReporter {
|
|
11
|
+
private options;
|
|
12
|
+
private startTime;
|
|
13
|
+
private totalTests;
|
|
14
|
+
private completedTests;
|
|
15
|
+
constructor(options?: ConsoleReporterOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Get executor callbacks for live reporting.
|
|
18
|
+
*/
|
|
19
|
+
getCallbacks(): ExecutorCallbacks;
|
|
20
|
+
/**
|
|
21
|
+
* Called when setup starts for an app.
|
|
22
|
+
*/
|
|
23
|
+
private onSetupStart;
|
|
24
|
+
/**
|
|
25
|
+
* Called when setup completes for an app.
|
|
26
|
+
*/
|
|
27
|
+
private onSetupComplete;
|
|
28
|
+
/**
|
|
29
|
+
* Called when a test run starts.
|
|
30
|
+
*/
|
|
31
|
+
private onRunStart;
|
|
32
|
+
/**
|
|
33
|
+
* Called when a test starts.
|
|
34
|
+
*/
|
|
35
|
+
private onTestStart;
|
|
36
|
+
/**
|
|
37
|
+
* Called when a test completes.
|
|
38
|
+
*/
|
|
39
|
+
private onTestComplete;
|
|
40
|
+
/**
|
|
41
|
+
* Called when a test is being retried.
|
|
42
|
+
*/
|
|
43
|
+
private onTestRetry;
|
|
44
|
+
/**
|
|
45
|
+
* Called when a test run completes.
|
|
46
|
+
*/
|
|
47
|
+
private onRunComplete;
|
|
48
|
+
/**
|
|
49
|
+
* Print the final summary.
|
|
50
|
+
*/
|
|
51
|
+
printSummary(result: RunResult): void;
|
|
52
|
+
/**
|
|
53
|
+
* Print detailed results (for verbose mode or separate report).
|
|
54
|
+
*/
|
|
55
|
+
printDetailedResults(result: RunResult): void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Print a preview of tests (for dry-run mode).
|
|
59
|
+
*/
|
|
60
|
+
export declare function printDryRunPreview(previews: Array<{
|
|
61
|
+
app: string;
|
|
62
|
+
rule: string;
|
|
63
|
+
severity: string;
|
|
64
|
+
steps: number;
|
|
65
|
+
prompt: string;
|
|
66
|
+
}>, showPrompts?: boolean): void;
|
|
67
|
+
/**
|
|
68
|
+
* Print validation results (for qualyx validate command).
|
|
69
|
+
*/
|
|
70
|
+
export declare function printValidationResult(filePath: string, valid: boolean, errors: string[], warnings: string[]): void;
|
|
71
|
+
/**
|
|
72
|
+
* Print a list of apps and rules (for qualyx list command).
|
|
73
|
+
*/
|
|
74
|
+
export declare function printList(apps: Array<{
|
|
75
|
+
name: string;
|
|
76
|
+
url: string;
|
|
77
|
+
rules: Array<{
|
|
78
|
+
id: string;
|
|
79
|
+
name: string;
|
|
80
|
+
severity: string;
|
|
81
|
+
}>;
|
|
82
|
+
}>): void;
|
|
83
|
+
//# sourceMappingURL=console.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/reporters/console.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAyB,SAAS,EAAc,MAAM,mBAAmB,CAAC;AACtF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAqDD;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,cAAc,CAAa;gBAEvB,OAAO,GAAE,sBAA2B;IAIhD;;OAEG;IACH,YAAY,IAAI,iBAAiB;IAYjC;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,OAAO,CAAC,eAAe;IAYvB;;OAEG;IACH,OAAO,CAAC,UAAU;IAWlB;;OAEG;IACH,OAAO,CAAC,WAAW;IAMnB;;OAEG;IACH,OAAO,CAAC,cAAc;IAoCtB;;OAEG;IACH,OAAO,CAAC,WAAW;IAMnB;;OAEG;IACH,OAAO,CAAC,aAAa;IAKrB;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAiCrC;;OAEG;IACH,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;CAqC9C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,KAAK,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,EACF,WAAW,GAAE,OAAe,GAC3B,IAAI,CA2BN;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EAAE,EAChB,QAAQ,EAAE,MAAM,EAAE,GACjB,IAAI,CAqBN;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,GACvG,IAAI,CAmBN"}
|