@aqa-pulse/cli 0.1.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/README.md +43 -0
- package/bin/aqa-pulse.js +49 -0
- package/dist/backend/generate-source-facts.d.ts +2 -0
- package/dist/backend/generate-source-facts.js +607 -0
- package/dist/backend/merge-reports.d.ts +19 -0
- package/dist/backend/merge-reports.js +314 -0
- package/dist/backend/upload-report-artifacts.d.ts +9 -0
- package/dist/backend/upload-report-artifacts.js +772 -0
- package/dist/backend/upload-report.d.ts +13 -0
- package/dist/backend/upload-report.js +338 -0
- package/dist/dashboard-utils.d.ts +437 -0
- package/dist/dashboard-utils.js +2627 -0
- package/dist/history-utils.d.ts +72 -0
- package/dist/history-utils.js +267 -0
- package/dist/shared/business-assumptions.d.ts +14 -0
- package/dist/shared/business-assumptions.js +61 -0
- package/dist/shared/dashboard-helpers.d.ts +63 -0
- package/dist/shared/dashboard-helpers.js +429 -0
- package/dist/shared/dashboard-metric-info.d.ts +61 -0
- package/dist/shared/dashboard-metric-info.js +15 -0
- package/dist/shared/error-utils.d.ts +1 -0
- package/dist/shared/error-utils.js +6 -0
- package/dist/shared/formatting.d.ts +3 -0
- package/dist/shared/formatting.js +42 -0
- package/dist/shared/i18n/ru.d.ts +558 -0
- package/dist/shared/i18n/ru.js +577 -0
- package/dist/shared/metric-info.d.ts +5 -0
- package/dist/shared/metric-info.js +210 -0
- package/dist/shared/navigation.d.ts +31 -0
- package/dist/shared/navigation.js +99 -0
- package/dist/shared/test-history-helpers.d.ts +51 -0
- package/dist/shared/test-history-helpers.js +294 -0
- package/dist/shared/test-history-metric-info.d.ts +17 -0
- package/dist/shared/test-history-metric-info.js +20 -0
- package/dist/shared/text-utils.d.ts +2 -0
- package/dist/shared/text-utils.js +15 -0
- package/package.json +37 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type DashboardRunMetadata, type PrecomputedCodeQualitySourceFacts } from '../dashboard-utils';
|
|
2
|
+
import type { IngestionResult } from './contracts';
|
|
3
|
+
export interface UploadReportOptions {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
workspaceSlug: string;
|
|
6
|
+
workspaceApiKey: string;
|
|
7
|
+
reportPath: string;
|
|
8
|
+
sourceFile: string;
|
|
9
|
+
sourceFactsPath: string | null;
|
|
10
|
+
precomputedSourceFacts: PrecomputedCodeQualitySourceFacts | null;
|
|
11
|
+
metadata: Partial<DashboardRunMetadata>;
|
|
12
|
+
}
|
|
13
|
+
export declare function uploadReportToWorkspace(options: UploadReportOptions): Promise<IngestionResult>;
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.uploadReportToWorkspace = uploadReportToWorkspace;
|
|
37
|
+
/**
|
|
38
|
+
* Назначение: консольная утилита для загрузки отчётов из CI или вручную.
|
|
39
|
+
* Она обменивает ключ workspace на токен загрузки и отправляет отчёт
|
|
40
|
+
* в self-hosted backend без участия интерфейса.
|
|
41
|
+
*/
|
|
42
|
+
const fs = __importStar(require("node:fs"));
|
|
43
|
+
const path = __importStar(require("node:path"));
|
|
44
|
+
const error_utils_1 = require("../shared/error-utils");
|
|
45
|
+
const dashboard_utils_1 = require("../dashboard-utils");
|
|
46
|
+
const upload_report_artifacts_1 = require("./upload-report-artifacts");
|
|
47
|
+
const generate_source_facts_1 = require("./generate-source-facts");
|
|
48
|
+
if (require.main === module) {
|
|
49
|
+
void main();
|
|
50
|
+
}
|
|
51
|
+
async function main() {
|
|
52
|
+
try {
|
|
53
|
+
const cliOptions = parseCliOptions(process.argv.slice(2));
|
|
54
|
+
const resolvedOptions = resolveUploadOptions(cliOptions);
|
|
55
|
+
const result = await uploadReportToWorkspace(resolvedOptions);
|
|
56
|
+
if (cliOptions.json) {
|
|
57
|
+
process.stdout.write(`${JSON.stringify({
|
|
58
|
+
workspaceSlug: resolvedOptions.workspaceSlug,
|
|
59
|
+
baseUrl: resolvedOptions.baseUrl,
|
|
60
|
+
reportPath: resolvedOptions.reportPath,
|
|
61
|
+
sourceFile: resolvedOptions.sourceFile,
|
|
62
|
+
sourceFactsPath: resolvedOptions.sourceFactsPath,
|
|
63
|
+
result,
|
|
64
|
+
}, null, 2)}\n`);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
printHumanReadableOutput(resolvedOptions, result);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error(`Ошибка upload report: ${(0, error_utils_1.getErrorMessage)(error)}`);
|
|
72
|
+
process.exitCode = 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function uploadReportToWorkspace(options) {
|
|
76
|
+
const accessToken = await exchangeWorkspaceApiKey(options);
|
|
77
|
+
const report = (0, upload_report_artifacts_1.prepareReporterReportForUpload)((0, dashboard_utils_1.loadReporterReport)(options.reportPath), {
|
|
78
|
+
reportPath: options.reportPath,
|
|
79
|
+
preparedReportPath: normalizeOptionalText(process.env.AQA_PULSE_PREPARED_REPORT_PATH),
|
|
80
|
+
debugAttachmentsSummary: isEnabledFlag(process.env.AQA_PULSE_DEBUG_ATTACHMENTS_SUMMARY),
|
|
81
|
+
inlineAttachmentsTotalMaxSizeBytes: parsePositiveInteger(process.env.AQA_PULSE_INLINE_ATTACHMENTS_TOTAL_MAX_SIZE_BYTES),
|
|
82
|
+
});
|
|
83
|
+
const payload = {
|
|
84
|
+
report,
|
|
85
|
+
metadata: {
|
|
86
|
+
branch: normalizeOptionalText(options.metadata.branch),
|
|
87
|
+
commit: normalizeOptionalText(options.metadata.commit),
|
|
88
|
+
author: normalizeOptionalText(options.metadata.author),
|
|
89
|
+
},
|
|
90
|
+
sourceFile: options.sourceFile,
|
|
91
|
+
precomputedSourceFacts: options.precomputedSourceFacts ?? undefined,
|
|
92
|
+
};
|
|
93
|
+
return postJson(`${options.baseUrl}/api/workspaces/${encodeURIComponent(options.workspaceSlug)}/ingestions`, payload, {
|
|
94
|
+
authorization: `Bearer ${accessToken}`,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function parseCliOptions(args) {
|
|
98
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
99
|
+
printHelp();
|
|
100
|
+
process.exit(0);
|
|
101
|
+
}
|
|
102
|
+
const options = { json: false };
|
|
103
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
104
|
+
const currentArg = args[index];
|
|
105
|
+
if (currentArg === '--json') {
|
|
106
|
+
options.json = true;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (currentArg === '--generate-source-facts') {
|
|
110
|
+
options.generateSourceFacts = true;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const nextArg = args[index + 1];
|
|
114
|
+
if (!nextArg || nextArg.startsWith('--')) {
|
|
115
|
+
throw new Error(`Для аргумента ${currentArg} нужно передать значение.`);
|
|
116
|
+
}
|
|
117
|
+
if (currentArg === '--base-url') {
|
|
118
|
+
options.baseUrl = nextArg;
|
|
119
|
+
index += 1;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (currentArg === '--workspace-slug') {
|
|
123
|
+
options.workspaceSlug = nextArg;
|
|
124
|
+
index += 1;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (currentArg === '--workspace-api-key') {
|
|
128
|
+
options.workspaceApiKey = nextArg;
|
|
129
|
+
index += 1;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (currentArg === '--report' || currentArg === '--report-path') {
|
|
133
|
+
options.reportPath = nextArg;
|
|
134
|
+
index += 1;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (currentArg === '--source-file') {
|
|
138
|
+
options.sourceFile = nextArg;
|
|
139
|
+
index += 1;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (currentArg === '--source-facts') {
|
|
143
|
+
options.sourceFactsPath = nextArg;
|
|
144
|
+
index += 1;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (currentArg === '--repo-root') {
|
|
148
|
+
options.repoRoot = nextArg;
|
|
149
|
+
index += 1;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (currentArg === '--branch') {
|
|
153
|
+
options.branch = nextArg;
|
|
154
|
+
index += 1;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (currentArg === '--commit') {
|
|
158
|
+
options.commit = nextArg;
|
|
159
|
+
index += 1;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (currentArg === '--author') {
|
|
163
|
+
options.author = nextArg;
|
|
164
|
+
index += 1;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
throw new Error(`Неизвестный аргумент: ${currentArg}`);
|
|
168
|
+
}
|
|
169
|
+
return options;
|
|
170
|
+
}
|
|
171
|
+
function resolveUploadOptions(options) {
|
|
172
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl ?? process.env.AQA_PULSE_BASE_URL);
|
|
173
|
+
const workspaceSlug = requireNonEmptyText(options.workspaceSlug ?? process.env.AQA_PULSE_WORKSPACE_SLUG, 'AQA_PULSE_WORKSPACE_SLUG');
|
|
174
|
+
const workspaceApiKey = requireNonEmptyText(options.workspaceApiKey ?? process.env.AQA_PULSE_WORKSPACE_API_KEY, 'AQA_PULSE_WORKSPACE_API_KEY');
|
|
175
|
+
const reportPath = requireNonEmptyText(options.reportPath ?? process.env.AQA_PULSE_REPORT_PATH ?? process.env.PW_LLM_REPORT ?? 'test-results/dashboard/data.json', '--report / AQA_PULSE_REPORT_PATH / PW_LLM_REPORT');
|
|
176
|
+
const sourceFile = normalizeOptionalText(options.sourceFile) ?? buildDefaultSourceFile(reportPath);
|
|
177
|
+
const shouldGenerateSourceFacts = options.generateSourceFacts === true || isEnabledFlag(process.env.AQA_PULSE_GENERATE_SOURCE_FACTS);
|
|
178
|
+
const sourceFactsPath = normalizeOptionalText(options.sourceFactsPath ?? process.env.AQA_PULSE_SOURCE_FACTS_PATH)
|
|
179
|
+
?? (shouldGenerateSourceFacts ? path.join(path.dirname(path.resolve(reportPath)), 'source-facts.json') : null);
|
|
180
|
+
const precomputedSourceFacts = sourceFactsPath
|
|
181
|
+
? resolvePrecomputedSourceFacts(sourceFactsPath, reportPath, options.repoRoot ?? process.env.AQA_PULSE_SOURCE_ROOT ?? process.env.AQA_PULSE_REPO_ROOT, shouldGenerateSourceFacts)
|
|
182
|
+
: null;
|
|
183
|
+
return {
|
|
184
|
+
baseUrl,
|
|
185
|
+
workspaceSlug,
|
|
186
|
+
workspaceApiKey,
|
|
187
|
+
reportPath,
|
|
188
|
+
sourceFile,
|
|
189
|
+
sourceFactsPath,
|
|
190
|
+
precomputedSourceFacts,
|
|
191
|
+
metadata: {
|
|
192
|
+
branch: normalizeOptionalText(options.branch ?? process.env.CI_COMMIT_REF_NAME ?? process.env.GITHUB_REF_NAME),
|
|
193
|
+
commit: normalizeOptionalText(options.commit ?? process.env.CI_COMMIT_SHA ?? process.env.GITHUB_SHA),
|
|
194
|
+
author: normalizeOptionalText(options.author ?? process.env.GITLAB_USER_NAME ?? process.env.CI_COMMIT_AUTHOR ?? process.env.GITHUB_ACTOR ?? 'CI upload'),
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
async function exchangeWorkspaceApiKey(options) {
|
|
199
|
+
const response = await fetch(`${options.baseUrl}/auth/workspaces/${encodeURIComponent(options.workspaceSlug)}/api-keys/login`, {
|
|
200
|
+
method: 'POST',
|
|
201
|
+
headers: {
|
|
202
|
+
'content-type': 'application/json',
|
|
203
|
+
},
|
|
204
|
+
body: JSON.stringify({ token: options.workspaceApiKey }),
|
|
205
|
+
});
|
|
206
|
+
const payload = await readJsonPayload(response);
|
|
207
|
+
if (!response.ok || !payload?.accessToken) {
|
|
208
|
+
throw new Error(readPayloadErrorMessage(payload, response.status, 'Не удалось получить ingestion JWT.'));
|
|
209
|
+
}
|
|
210
|
+
return payload.accessToken;
|
|
211
|
+
}
|
|
212
|
+
async function postJson(url, body, extraHeaders = {}) {
|
|
213
|
+
const response = await fetch(url, {
|
|
214
|
+
method: 'POST',
|
|
215
|
+
headers: {
|
|
216
|
+
'content-type': 'application/json',
|
|
217
|
+
...extraHeaders,
|
|
218
|
+
},
|
|
219
|
+
body: JSON.stringify(body),
|
|
220
|
+
});
|
|
221
|
+
const payload = await readJsonPayload(response);
|
|
222
|
+
if (!response.ok || payload === null) {
|
|
223
|
+
throw new Error(readPayloadErrorMessage(payload, response.status, 'Upload ingestion report завершился ошибкой.'));
|
|
224
|
+
}
|
|
225
|
+
return payload;
|
|
226
|
+
}
|
|
227
|
+
async function readJsonPayload(response) {
|
|
228
|
+
const text = await response.text();
|
|
229
|
+
if (!text.trim()) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
return JSON.parse(text);
|
|
233
|
+
}
|
|
234
|
+
function readPayloadErrorMessage(payload, status, fallback) {
|
|
235
|
+
return normalizeOptionalText(payload?.error) ?? `${fallback} HTTP ${status}.`;
|
|
236
|
+
}
|
|
237
|
+
function printHumanReadableOutput(options, result) {
|
|
238
|
+
console.log('AQA Pulse report upload завершён.');
|
|
239
|
+
console.log('');
|
|
240
|
+
console.log(`Workspace slug: ${options.workspaceSlug}`);
|
|
241
|
+
console.log(`Base URL: ${options.baseUrl}`);
|
|
242
|
+
console.log(`Report path: ${options.reportPath}`);
|
|
243
|
+
console.log(`Source file: ${options.sourceFile}`);
|
|
244
|
+
if (options.sourceFactsPath) {
|
|
245
|
+
console.log(`Source facts path: ${options.sourceFactsPath}`);
|
|
246
|
+
}
|
|
247
|
+
console.log(`Run id: ${result.runId}`);
|
|
248
|
+
console.log(`Summary generated at: ${result.summaryGeneratedAt}`);
|
|
249
|
+
console.log(`Dashboard summary path: ${result.summaryPath}`);
|
|
250
|
+
console.log(`History path: ${result.historyPath}`);
|
|
251
|
+
}
|
|
252
|
+
function printHelp() {
|
|
253
|
+
console.log('aqa-pulse-server upload-report [options]');
|
|
254
|
+
console.log('');
|
|
255
|
+
console.log('Опции:');
|
|
256
|
+
console.log(' --base-url <url> Base URL сервера, иначе AQA_PULSE_BASE_URL');
|
|
257
|
+
console.log(' --workspace-slug <slug> Workspace slug, иначе AQA_PULSE_WORKSPACE_SLUG');
|
|
258
|
+
console.log(' --workspace-api-key <key> Raw workspace API key, иначе AQA_PULSE_WORKSPACE_API_KEY');
|
|
259
|
+
console.log(' --report <path> Путь к report JSON, иначе AQA_PULSE_REPORT_PATH / PW_LLM_REPORT / test-results/dashboard/data.json');
|
|
260
|
+
console.log(' --source-file <value> Явный sourceFile для ingestion payload');
|
|
261
|
+
console.log(' --source-facts <path> JSON с precomputed source facts для code-quality metrics');
|
|
262
|
+
console.log(' --generate-source-facts Сгенерировать source-facts перед upload, если файл не найден');
|
|
263
|
+
console.log(' --repo-root <path> Корень repo для --generate-source-facts, иначе текущая директория');
|
|
264
|
+
console.log(' --branch <value> Явная branch metadata');
|
|
265
|
+
console.log(' --commit <value> Явная commit metadata');
|
|
266
|
+
console.log(' --author <value> Явный author metadata');
|
|
267
|
+
console.log(' --json Печатать результат в JSON');
|
|
268
|
+
console.log('');
|
|
269
|
+
console.log('Дополнительные env для attachment-aware upload:');
|
|
270
|
+
console.log(' AQA_PULSE_SOURCE_FACTS_PATH Путь к JSON с precomputed source facts');
|
|
271
|
+
console.log(' AQA_PULSE_GENERATE_SOURCE_FACTS=true Автоматически сгенерировать source facts перед upload');
|
|
272
|
+
console.log(' AQA_PULSE_SOURCE_ROOT / AQA_PULSE_REPO_ROOT Корень repo для генерации source facts');
|
|
273
|
+
console.log(' AQA_PULSE_PREPARED_REPORT_PATH Сохранить подготовленный payload report в JSON');
|
|
274
|
+
console.log(' AQA_PULSE_DEBUG_ATTACHMENTS_SUMMARY=true Печатать debug summary по найденным attachment');
|
|
275
|
+
console.log(' AQA_PULSE_INLINE_ATTACHMENTS_TOTAL_MAX_SIZE_BYTES Общий budget inline attachment в байтах');
|
|
276
|
+
}
|
|
277
|
+
function normalizeBaseUrl(value) {
|
|
278
|
+
const normalized = requireNonEmptyText(value, 'AQA_PULSE_BASE_URL').replace(/\/+$/g, '');
|
|
279
|
+
if (!/^https?:\/\//i.test(normalized)) {
|
|
280
|
+
throw new Error(`Base URL должен начинаться с http:// или https://, получено: ${normalized}`);
|
|
281
|
+
}
|
|
282
|
+
return normalized;
|
|
283
|
+
}
|
|
284
|
+
function buildDefaultSourceFile(reportPath) {
|
|
285
|
+
const gitlabProjectPath = normalizeOptionalText(process.env.CI_PROJECT_PATH);
|
|
286
|
+
const gitlabPipelineId = normalizeOptionalText(process.env.CI_PIPELINE_ID);
|
|
287
|
+
const gitlabJobName = normalizeOptionalText(process.env.CI_JOB_NAME);
|
|
288
|
+
if (gitlabProjectPath && gitlabPipelineId && gitlabJobName) {
|
|
289
|
+
return `gitlab://${gitlabProjectPath}/${gitlabPipelineId}/${gitlabJobName}`;
|
|
290
|
+
}
|
|
291
|
+
const githubRepository = normalizeOptionalText(process.env.GITHUB_REPOSITORY);
|
|
292
|
+
const githubRunId = normalizeOptionalText(process.env.GITHUB_RUN_ID);
|
|
293
|
+
const githubJob = normalizeOptionalText(process.env.GITHUB_JOB);
|
|
294
|
+
if (githubRepository && githubRunId && githubJob) {
|
|
295
|
+
return `github://${githubRepository}/${githubRunId}/${githubJob}`;
|
|
296
|
+
}
|
|
297
|
+
return `manual://${reportPath.replace(/\\/g, '/')}`;
|
|
298
|
+
}
|
|
299
|
+
function requireNonEmptyText(value, label) {
|
|
300
|
+
const normalized = normalizeOptionalText(value);
|
|
301
|
+
if (!normalized) {
|
|
302
|
+
throw new Error(`Нужно передать ${label}.`);
|
|
303
|
+
}
|
|
304
|
+
return normalized;
|
|
305
|
+
}
|
|
306
|
+
function normalizeOptionalText(value) {
|
|
307
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;
|
|
308
|
+
}
|
|
309
|
+
function parsePositiveInteger(value) {
|
|
310
|
+
if (!value || value.trim().length === 0) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
const parsed = Number(value);
|
|
314
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
|
|
315
|
+
}
|
|
316
|
+
function isEnabledFlag(value) {
|
|
317
|
+
const normalized = normalizeOptionalText(value)?.toLowerCase();
|
|
318
|
+
return normalized === '1' || normalized === 'true' || normalized === 'yes';
|
|
319
|
+
}
|
|
320
|
+
function readJsonFile(filePath, label) {
|
|
321
|
+
const resolvedFilePath = requireNonEmptyText(filePath, label);
|
|
322
|
+
const fileContent = fs.readFileSync(resolvedFilePath, 'utf8');
|
|
323
|
+
return JSON.parse(fileContent);
|
|
324
|
+
}
|
|
325
|
+
function resolvePrecomputedSourceFacts(sourceFactsPath, reportPath, repoRoot, shouldGenerate) {
|
|
326
|
+
if (fs.existsSync(sourceFactsPath)) {
|
|
327
|
+
return readJsonFile(sourceFactsPath, '--source-facts / AQA_PULSE_SOURCE_FACTS_PATH');
|
|
328
|
+
}
|
|
329
|
+
if (!shouldGenerate) {
|
|
330
|
+
throw new Error(`Не найден source facts file: ${sourceFactsPath}`);
|
|
331
|
+
}
|
|
332
|
+
const report = (0, dashboard_utils_1.loadReporterReport)(reportPath);
|
|
333
|
+
const resolvedRepoRoot = path.resolve(repoRoot ?? process.cwd());
|
|
334
|
+
const sourceFacts = (0, generate_source_facts_1.buildPrecomputedSourceFacts)(report, resolvedRepoRoot, path.resolve(reportPath));
|
|
335
|
+
fs.mkdirSync(path.dirname(path.resolve(sourceFactsPath)), { recursive: true });
|
|
336
|
+
fs.writeFileSync(sourceFactsPath, `${JSON.stringify(sourceFacts, null, 2)}\n`, 'utf8');
|
|
337
|
+
return sourceFacts;
|
|
338
|
+
}
|