airgen-cli 0.1.3 → 0.1.4
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/dist/commands/reports.js +27 -15
- package/package.json +1 -1
package/dist/commands/reports.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { output, printTable, isJsonMode, truncate } from "../output.js";
|
|
2
2
|
const IMPL_TAG_PREFIX = "impl:";
|
|
3
3
|
const IMPL_STATUSES = ["not_started", "in_progress", "implemented", "verified", "blocked"];
|
|
4
|
+
const PAGE_SIZE = 100;
|
|
5
|
+
const MAX_PAGES = 50;
|
|
4
6
|
function getImplStatus(tags) {
|
|
5
7
|
if (!tags)
|
|
6
8
|
return null;
|
|
@@ -10,6 +12,21 @@ function getImplStatus(tags) {
|
|
|
10
12
|
const status = implTag.slice(IMPL_TAG_PREFIX.length);
|
|
11
13
|
return IMPL_STATUSES.includes(status) ? status : null;
|
|
12
14
|
}
|
|
15
|
+
async function fetchAllRequirements(client, tenant, project) {
|
|
16
|
+
const all = [];
|
|
17
|
+
for (let page = 1; page <= MAX_PAGES; page++) {
|
|
18
|
+
const data = await client.get(`/requirements/${tenant}/${project}`, {
|
|
19
|
+
page: String(page),
|
|
20
|
+
limit: String(PAGE_SIZE),
|
|
21
|
+
});
|
|
22
|
+
const items = data.data ?? [];
|
|
23
|
+
all.push(...items);
|
|
24
|
+
const totalPages = data.meta?.totalPages ?? 1;
|
|
25
|
+
if (page >= totalPages)
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
return all.filter(r => !r.deleted && !r.deletedAt);
|
|
29
|
+
}
|
|
13
30
|
export function registerReportCommands(program, client) {
|
|
14
31
|
const cmd = program.command("reports").alias("report").description("Project reports");
|
|
15
32
|
cmd
|
|
@@ -44,10 +61,8 @@ export function registerReportCommands(program, client) {
|
|
|
44
61
|
.description("Quality score summary")
|
|
45
62
|
.argument("<tenant>", "Tenant slug")
|
|
46
63
|
.argument("<project>", "Project slug")
|
|
47
|
-
.
|
|
48
|
-
|
|
49
|
-
const data = await client.get(`/requirements/${tenant}/${project}`, { page: "1", limit: opts.limit });
|
|
50
|
-
const reqs = data.data ?? [];
|
|
64
|
+
.action(async (tenant, project) => {
|
|
65
|
+
const reqs = await fetchAllRequirements(client, tenant, project);
|
|
51
66
|
const scored = reqs.filter(r => r.qaScore != null);
|
|
52
67
|
const avg = scored.length > 0
|
|
53
68
|
? scored.reduce((sum, r) => sum + (r.qaScore ?? 0), 0) / scored.length
|
|
@@ -72,13 +87,11 @@ export function registerReportCommands(program, client) {
|
|
|
72
87
|
});
|
|
73
88
|
cmd
|
|
74
89
|
.command("compliance")
|
|
75
|
-
.description("Compliance status summary")
|
|
90
|
+
.description("Compliance and implementation status summary")
|
|
76
91
|
.argument("<tenant>", "Tenant slug")
|
|
77
92
|
.argument("<project>", "Project slug")
|
|
78
|
-
.
|
|
79
|
-
|
|
80
|
-
const data = await client.get(`/requirements/${tenant}/${project}`, { page: "1", limit: opts.limit });
|
|
81
|
-
const reqs = data.data ?? [];
|
|
93
|
+
.action(async (tenant, project) => {
|
|
94
|
+
const reqs = await fetchAllRequirements(client, tenant, project);
|
|
82
95
|
// Compliance status
|
|
83
96
|
const compCounts = {};
|
|
84
97
|
for (const r of reqs) {
|
|
@@ -98,9 +111,10 @@ export function registerReportCommands(program, client) {
|
|
|
98
111
|
implCounts["unset"]++;
|
|
99
112
|
}
|
|
100
113
|
if (isJsonMode()) {
|
|
101
|
-
output({ compliance: compCounts, implementation: implCounts });
|
|
114
|
+
output({ total: reqs.length, compliance: compCounts, implementation: implCounts });
|
|
102
115
|
}
|
|
103
116
|
else {
|
|
117
|
+
console.log(`Total requirements: ${reqs.length}\n`);
|
|
104
118
|
console.log("Compliance Status:");
|
|
105
119
|
printTable(["Status", "Count"], Object.entries(compCounts).map(([k, v]) => [k, String(v)]));
|
|
106
120
|
console.log("\nImplementation Status:");
|
|
@@ -112,13 +126,11 @@ export function registerReportCommands(program, client) {
|
|
|
112
126
|
.description("Find requirements with no trace links")
|
|
113
127
|
.argument("<tenant>", "Tenant slug")
|
|
114
128
|
.argument("<project>", "Project slug")
|
|
115
|
-
.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
client.get(`/requirements/${tenant}/${project}`, { page: "1", limit: opts.limit }),
|
|
129
|
+
.action(async (tenant, project) => {
|
|
130
|
+
const [reqs, linkData] = await Promise.all([
|
|
131
|
+
fetchAllRequirements(client, tenant, project),
|
|
119
132
|
client.get(`/trace-links/${tenant}/${project}`),
|
|
120
133
|
]);
|
|
121
|
-
const reqs = reqData.data ?? [];
|
|
122
134
|
const links = linkData.links ?? [];
|
|
123
135
|
const linked = new Set();
|
|
124
136
|
for (const l of links) {
|