@qanalyzer/forge-commons 1.1.1
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 +202 -0
- package/dist/ci/context.d.ts +6 -0
- package/dist/ci/context.js +71 -0
- package/dist/ci/frameworks/jest.d.ts +1 -0
- package/dist/ci/frameworks/jest.js +6 -0
- package/dist/ci/frameworks/reporter.d.ts +41 -0
- package/dist/ci/frameworks/reporter.js +184 -0
- package/dist/ci/frameworks/upload.d.ts +10 -0
- package/dist/ci/frameworks/upload.js +58 -0
- package/dist/ci/frameworks/vitest.d.ts +2 -0
- package/dist/ci/frameworks/vitest.js +10 -0
- package/dist/ci/generate-ci-template.d.ts +7 -0
- package/dist/ci/generate-ci-template.js +79 -0
- package/dist/ci/index.d.ts +7 -0
- package/dist/ci/index.js +36 -0
- package/dist/ci/templates/azure-devops.d.ts +5 -0
- package/dist/ci/templates/azure-devops.js +142 -0
- package/dist/ci/templates/bitbucket.d.ts +5 -0
- package/dist/ci/templates/bitbucket.js +113 -0
- package/dist/ci/templates/github.d.ts +6 -0
- package/dist/ci/templates/github.js +156 -0
- package/dist/ci/templates/gitlab.d.ts +5 -0
- package/dist/ci/templates/gitlab.js +124 -0
- package/dist/ci/templates/jenkins.d.ts +5 -0
- package/dist/ci/templates/jenkins.js +125 -0
- package/dist/ci/types.d.ts +58 -0
- package/dist/ci/types.js +16 -0
- package/dist/client/attach-client.d.ts +48 -0
- package/dist/client/attach-client.js +122 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +8 -0
- package/dist/client/ingest-client.d.ts +19 -0
- package/dist/client/ingest-client.js +66 -0
- package/dist/config/config-loader.d.ts +8 -0
- package/dist/config/config-loader.js +62 -0
- package/dist/config/config-type.d.ts +24 -0
- package/dist/config/config-type.js +2 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +6 -0
- package/dist/env/ci-environment.d.ts +10 -0
- package/dist/env/ci-environment.js +59 -0
- package/dist/env/env-enum.d.ts +21 -0
- package/dist/env/env-enum.js +27 -0
- package/dist/env/env-to-config.d.ts +3 -0
- package/dist/env/env-to-config.js +53 -0
- package/dist/env/index.d.ts +4 -0
- package/dist/env/index.js +11 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +59 -0
- package/dist/models/attachment.d.ts +9 -0
- package/dist/models/attachment.js +2 -0
- package/dist/models/execution-sum.d.ts +7 -0
- package/dist/models/execution-sum.js +2 -0
- package/dist/models/host-data.d.ts +13 -0
- package/dist/models/host-data.js +2 -0
- package/dist/models/index.d.ts +14 -0
- package/dist/models/index.js +24 -0
- package/dist/models/ingest-payload.d.ts +56 -0
- package/dist/models/ingest-payload.js +56 -0
- package/dist/models/jest-vitest-report.d.ts +37 -0
- package/dist/models/jest-vitest-report.js +2 -0
- package/dist/models/meta-qa.d.ts +71 -0
- package/dist/models/meta-qa.js +257 -0
- package/dist/models/report.d.ts +15 -0
- package/dist/models/report.js +2 -0
- package/dist/models/short-result.d.ts +8 -0
- package/dist/models/short-result.js +2 -0
- package/dist/models/stats.d.ts +10 -0
- package/dist/models/stats.js +2 -0
- package/dist/models/step-data.d.ts +20 -0
- package/dist/models/step-data.js +2 -0
- package/dist/models/step-execution.d.ts +14 -0
- package/dist/models/step-execution.js +24 -0
- package/dist/models/test-execution.d.ts +18 -0
- package/dist/models/test-execution.js +30 -0
- package/dist/models/test-result.d.ts +34 -0
- package/dist/models/test-result.js +43 -0
- package/dist/models/test-step.d.ts +19 -0
- package/dist/models/test-step.js +46 -0
- package/dist/options/compose-options.d.ts +2 -0
- package/dist/options/compose-options.js +26 -0
- package/dist/options/index.d.ts +3 -0
- package/dist/options/index.js +7 -0
- package/dist/options/mode-enum.d.ts +5 -0
- package/dist/options/mode-enum.js +9 -0
- package/dist/options/options-type.d.ts +11 -0
- package/dist/options/options-type.js +2 -0
- package/dist/qanalyzer/index.d.ts +2 -0
- package/dist/qanalyzer/index.js +8 -0
- package/dist/qanalyzer/options-resolver.d.ts +11 -0
- package/dist/qanalyzer/options-resolver.js +31 -0
- package/dist/qanalyzer/reporter-factory.d.ts +11 -0
- package/dist/qanalyzer/reporter-factory.js +51 -0
- package/dist/qanalyzer.d.ts +29 -0
- package/dist/qanalyzer.js +96 -0
- package/dist/reporters/fallback-coordinator.d.ts +24 -0
- package/dist/reporters/fallback-coordinator.js +77 -0
- package/dist/reporters/file-reporter.d.ts +10 -0
- package/dist/reporters/file-reporter.js +16 -0
- package/dist/reporters/index.d.ts +4 -0
- package/dist/reporters/index.js +9 -0
- package/dist/reporters/ingest-reporter.d.ts +9 -0
- package/dist/reporters/ingest-reporter.js +14 -0
- package/dist/reporters/reporter-interface.d.ts +4 -0
- package/dist/reporters/reporter-interface.js +2 -0
- package/dist/utils/disabled-exception.d.ts +2 -0
- package/dist/utils/disabled-exception.js +6 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.js +17 -0
- package/dist/utils/issue-keys.d.ts +7 -0
- package/dist/utils/issue-keys.js +33 -0
- package/dist/utils/logger.d.ts +12 -0
- package/dist/utils/logger.js +21 -0
- package/dist/utils/token-masker.d.ts +2 -0
- package/dist/utils/token-masker.js +17 -0
- package/dist/utils/upload-attachment.d.ts +35 -0
- package/dist/utils/upload-attachment.js +158 -0
- package/dist/writer/fs-writer.d.ts +9 -0
- package/dist/writer/fs-writer.js +19 -0
- package/dist/writer/index.d.ts +1 -0
- package/dist/writer/index.js +5 -0
- package/package.json +34 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OptionsResolver = void 0;
|
|
4
|
+
exports.createDefaultConfig = createDefaultConfig;
|
|
5
|
+
const env_1 = require("../env");
|
|
6
|
+
const options_1 = require("../options");
|
|
7
|
+
class OptionsResolver {
|
|
8
|
+
resolve(options = {}) {
|
|
9
|
+
const composed = (0, options_1.composeOptions)(createDefaultConfig(), options, (0, env_1.envToConfig)());
|
|
10
|
+
return {
|
|
11
|
+
effectiveMode: composed.mode ?? options_1.ModeEnum.off,
|
|
12
|
+
effectiveFallback: composed.fallback ?? options_1.ModeEnum.off,
|
|
13
|
+
composed,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.OptionsResolver = OptionsResolver;
|
|
18
|
+
function createDefaultConfig() {
|
|
19
|
+
return {
|
|
20
|
+
mode: options_1.ModeEnum.off,
|
|
21
|
+
fallback: options_1.ModeEnum.off,
|
|
22
|
+
debug: false,
|
|
23
|
+
ingest: {
|
|
24
|
+
timeoutMs: 30_000,
|
|
25
|
+
maxPayloadBytes: 4_500_000,
|
|
26
|
+
},
|
|
27
|
+
file: {
|
|
28
|
+
path: './qanalyzer-results.json',
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ConfigType } from '../config';
|
|
2
|
+
import { ModeEnum, type OptionsType } from '../options';
|
|
3
|
+
import { type InternalReporterInterface } from '../reporters';
|
|
4
|
+
import { type LoggerInterface } from '../utils';
|
|
5
|
+
export declare class ReporterFactory {
|
|
6
|
+
private readonly logger;
|
|
7
|
+
constructor(logger: LoggerInterface);
|
|
8
|
+
create(mode: ModeEnum, options: ConfigType & OptionsType): InternalReporterInterface;
|
|
9
|
+
private createIngest;
|
|
10
|
+
private createFile;
|
|
11
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReporterFactory = void 0;
|
|
4
|
+
const client_1 = require("../client");
|
|
5
|
+
const env_1 = require("../env");
|
|
6
|
+
const options_1 = require("../options");
|
|
7
|
+
const reporters_1 = require("../reporters");
|
|
8
|
+
const utils_1 = require("../utils");
|
|
9
|
+
const writer_1 = require("../writer");
|
|
10
|
+
class ReporterFactory {
|
|
11
|
+
logger;
|
|
12
|
+
constructor(logger) {
|
|
13
|
+
this.logger = logger;
|
|
14
|
+
}
|
|
15
|
+
create(mode, options) {
|
|
16
|
+
switch (mode) {
|
|
17
|
+
case options_1.ModeEnum.ingest:
|
|
18
|
+
return this.createIngest(options);
|
|
19
|
+
case options_1.ModeEnum.file:
|
|
20
|
+
return this.createFile(options);
|
|
21
|
+
case options_1.ModeEnum.off:
|
|
22
|
+
throw new utils_1.DisabledException('QAnalyzer reporter is disabled (mode=off)');
|
|
23
|
+
default:
|
|
24
|
+
throw new Error(`Unknown mode: ${String(mode)}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
createIngest(options) {
|
|
28
|
+
if (!options.ingest?.token) {
|
|
29
|
+
throw new Error(`Either "ingest.token" or "${env_1.EnvIngestEnum.token}" is required in ingest mode`);
|
|
30
|
+
}
|
|
31
|
+
if (!options.ingest?.url) {
|
|
32
|
+
throw new Error(`Either "ingest.url" or "${env_1.EnvIngestEnum.url}" is required in ingest mode`);
|
|
33
|
+
}
|
|
34
|
+
if (!options.projectKey) {
|
|
35
|
+
throw new Error('projectKey is required in ingest mode');
|
|
36
|
+
}
|
|
37
|
+
const client = new client_1.IngestClient({
|
|
38
|
+
...options.ingest,
|
|
39
|
+
logger: this.logger,
|
|
40
|
+
});
|
|
41
|
+
return new reporters_1.IngestReporter(this.logger, client);
|
|
42
|
+
}
|
|
43
|
+
createFile(options) {
|
|
44
|
+
if (!options.projectKey) {
|
|
45
|
+
throw new Error('projectKey is required in file mode');
|
|
46
|
+
}
|
|
47
|
+
const writer = new writer_1.FsWriter(options.file);
|
|
48
|
+
return new reporters_1.FileReporter(this.logger, writer);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.ReporterFactory = ReporterFactory;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ConfigType } from './config';
|
|
2
|
+
import { type IngestPayload, type JestVitestJsonReport } from './models';
|
|
3
|
+
import { type OptionsType } from './options';
|
|
4
|
+
export type PublishReportOptions = {
|
|
5
|
+
projectKey?: string;
|
|
6
|
+
launchName?: string;
|
|
7
|
+
format?: IngestPayload['format'];
|
|
8
|
+
planId?: string;
|
|
9
|
+
planKey?: string;
|
|
10
|
+
planName?: string;
|
|
11
|
+
fixVersion?: string;
|
|
12
|
+
sprintName?: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Thin orchestrator over OptionsResolver, ReporterFactory, and FallbackCoordinator.
|
|
16
|
+
* Framework adapters call `publishReport` with runner JSON at end of test run.
|
|
17
|
+
*/
|
|
18
|
+
export declare class QAnalyzerReporter {
|
|
19
|
+
private static instance;
|
|
20
|
+
private readonly options;
|
|
21
|
+
private readonly logger;
|
|
22
|
+
private readonly fallback;
|
|
23
|
+
private constructor();
|
|
24
|
+
static getInstance(options?: OptionsType): QAnalyzerReporter;
|
|
25
|
+
static resetInstance(): void;
|
|
26
|
+
getConfig(): ConfigType & OptionsType;
|
|
27
|
+
publishReport(report: JestVitestJsonReport, overrides?: PublishReportOptions): Promise<IngestPayload | undefined>;
|
|
28
|
+
private buildReporters;
|
|
29
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QAnalyzerReporter = void 0;
|
|
4
|
+
const env_1 = require("./env");
|
|
5
|
+
const models_1 = require("./models");
|
|
6
|
+
const options_1 = require("./options");
|
|
7
|
+
const reporters_1 = require("./reporters");
|
|
8
|
+
const utils_1 = require("./utils");
|
|
9
|
+
const options_resolver_1 = require("./qanalyzer/options-resolver");
|
|
10
|
+
const reporter_factory_1 = require("./qanalyzer/reporter-factory");
|
|
11
|
+
/**
|
|
12
|
+
* Thin orchestrator over OptionsResolver, ReporterFactory, and FallbackCoordinator.
|
|
13
|
+
* Framework adapters call `publishReport` with runner JSON at end of test run.
|
|
14
|
+
*/
|
|
15
|
+
class QAnalyzerReporter {
|
|
16
|
+
static instance = null;
|
|
17
|
+
options;
|
|
18
|
+
logger;
|
|
19
|
+
fallback;
|
|
20
|
+
constructor(options = {}) {
|
|
21
|
+
const resolved = new options_resolver_1.OptionsResolver().resolve(options);
|
|
22
|
+
this.options = resolved.composed;
|
|
23
|
+
this.logger = new utils_1.Logger(Boolean(this.options.debug));
|
|
24
|
+
this.logger.logDebug(`Config: ${JSON.stringify((0, utils_1.sanitizeOptionsForLog)(resolved.composed))}`);
|
|
25
|
+
const factory = new reporter_factory_1.ReporterFactory(this.logger);
|
|
26
|
+
const { upstream, fallback, disabled } = this.buildReporters(factory, resolved.effectiveMode, resolved.effectiveFallback);
|
|
27
|
+
this.fallback = new reporters_1.FallbackCoordinator(this.logger, upstream, fallback);
|
|
28
|
+
if (disabled) {
|
|
29
|
+
this.fallback.setDisabled(true);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
static getInstance(options = {}) {
|
|
33
|
+
if (!QAnalyzerReporter.instance) {
|
|
34
|
+
QAnalyzerReporter.instance = new QAnalyzerReporter(options);
|
|
35
|
+
}
|
|
36
|
+
return QAnalyzerReporter.instance;
|
|
37
|
+
}
|
|
38
|
+
static resetInstance() {
|
|
39
|
+
QAnalyzerReporter.instance = null;
|
|
40
|
+
}
|
|
41
|
+
getConfig() {
|
|
42
|
+
return this.options;
|
|
43
|
+
}
|
|
44
|
+
async publishReport(report, overrides = {}) {
|
|
45
|
+
const projectKey = overrides.projectKey ?? this.options.projectKey;
|
|
46
|
+
if (!projectKey) {
|
|
47
|
+
throw new Error('projectKey is required to publish a report');
|
|
48
|
+
}
|
|
49
|
+
const payload = (0, models_1.buildIngestPayload)({
|
|
50
|
+
projectKey,
|
|
51
|
+
report,
|
|
52
|
+
launchName: overrides.launchName ?? this.options.launchName,
|
|
53
|
+
format: overrides.format,
|
|
54
|
+
planId: overrides.planId ?? this.options.planId,
|
|
55
|
+
planKey: overrides.planKey ?? this.options.planKey,
|
|
56
|
+
planName: overrides.planName ?? this.options.planName,
|
|
57
|
+
fixVersion: overrides.fixVersion ?? this.options.fixVersion,
|
|
58
|
+
sprintName: overrides.sprintName ?? this.options.sprintName,
|
|
59
|
+
ci: (0, env_1.detectCiEnvironment)(),
|
|
60
|
+
});
|
|
61
|
+
if (this.fallback.isDisabled()) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
await this.fallback.run((reporter) => reporter.publishPayload(payload), 'publish report');
|
|
65
|
+
return payload;
|
|
66
|
+
}
|
|
67
|
+
buildReporters(factory, mode, fallbackMode) {
|
|
68
|
+
let upstream;
|
|
69
|
+
let fallback;
|
|
70
|
+
let disabled = false;
|
|
71
|
+
try {
|
|
72
|
+
upstream = factory.create(mode, this.options);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (error instanceof utils_1.DisabledException) {
|
|
76
|
+
disabled = true;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this.logger.logError('Unable to create upstream reporter', error);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (fallbackMode !== options_1.ModeEnum.off && fallbackMode !== mode) {
|
|
83
|
+
try {
|
|
84
|
+
fallback = factory.create(fallbackMode, this.options);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
this.logger.logError('Unable to create fallback reporter', error);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (!upstream && !fallback) {
|
|
91
|
+
disabled = true;
|
|
92
|
+
}
|
|
93
|
+
return { upstream, fallback, disabled };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.QAnalyzerReporter = QAnalyzerReporter;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { LoggerInterface } from '../utils';
|
|
2
|
+
import type { InternalReporterInterface } from './reporter-interface';
|
|
3
|
+
export type FallbackCoordinatorCallbacks = {
|
|
4
|
+
onUpstreamFailure?: () => void;
|
|
5
|
+
onFallbackFailure?: () => void;
|
|
6
|
+
onFallbackActivated?: () => void;
|
|
7
|
+
onDisabled?: () => void;
|
|
8
|
+
};
|
|
9
|
+
/** Upstream ingest → fallback file cascade. */
|
|
10
|
+
export declare class FallbackCoordinator {
|
|
11
|
+
private readonly logger;
|
|
12
|
+
private readonly upstream;
|
|
13
|
+
private readonly fallback;
|
|
14
|
+
private readonly callbacks;
|
|
15
|
+
private useFallback;
|
|
16
|
+
private disabled;
|
|
17
|
+
private onDisabledFired;
|
|
18
|
+
constructor(logger: LoggerInterface, upstream: InternalReporterInterface | undefined, fallback: InternalReporterInterface | undefined, callbacks?: FallbackCoordinatorCallbacks);
|
|
19
|
+
isDisabled(): boolean;
|
|
20
|
+
setDisabled(value: boolean): void;
|
|
21
|
+
run<T>(op: (reporter: InternalReporterInterface) => Promise<T>, opName: string): Promise<T | undefined>;
|
|
22
|
+
private disable;
|
|
23
|
+
private runOnFallback;
|
|
24
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FallbackCoordinator = void 0;
|
|
4
|
+
/** Upstream ingest → fallback file cascade. */
|
|
5
|
+
class FallbackCoordinator {
|
|
6
|
+
logger;
|
|
7
|
+
upstream;
|
|
8
|
+
fallback;
|
|
9
|
+
callbacks;
|
|
10
|
+
useFallback = false;
|
|
11
|
+
disabled = false;
|
|
12
|
+
onDisabledFired = false;
|
|
13
|
+
constructor(logger, upstream, fallback, callbacks = {}) {
|
|
14
|
+
this.logger = logger;
|
|
15
|
+
this.upstream = upstream;
|
|
16
|
+
this.fallback = fallback;
|
|
17
|
+
this.callbacks = callbacks;
|
|
18
|
+
}
|
|
19
|
+
isDisabled() {
|
|
20
|
+
return this.disabled;
|
|
21
|
+
}
|
|
22
|
+
setDisabled(value) {
|
|
23
|
+
this.disabled = value;
|
|
24
|
+
}
|
|
25
|
+
async run(op, opName) {
|
|
26
|
+
if (this.disabled)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (this.useFallback) {
|
|
29
|
+
return this.runOnFallback(op, opName);
|
|
30
|
+
}
|
|
31
|
+
if (!this.upstream) {
|
|
32
|
+
if (!this.fallback)
|
|
33
|
+
return undefined;
|
|
34
|
+
this.useFallback = true;
|
|
35
|
+
return this.runOnFallback(op, opName);
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
return await op(this.upstream);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
this.logger.logError(`Unable to ${opName} in the upstream reporter`, error);
|
|
42
|
+
this.callbacks.onUpstreamFailure?.();
|
|
43
|
+
if (!this.fallback) {
|
|
44
|
+
this.disable();
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
this.useFallback = true;
|
|
48
|
+
this.callbacks.onFallbackActivated?.();
|
|
49
|
+
return this.runOnFallback(op, opName);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
disable() {
|
|
53
|
+
if (this.disabled)
|
|
54
|
+
return;
|
|
55
|
+
this.disabled = true;
|
|
56
|
+
if (!this.onDisabledFired) {
|
|
57
|
+
this.onDisabledFired = true;
|
|
58
|
+
this.callbacks.onDisabled?.();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async runOnFallback(op, opName) {
|
|
62
|
+
if (!this.fallback) {
|
|
63
|
+
this.disable();
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
return await op(this.fallback);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
this.logger.logError(`Unable to ${opName} in the fallback reporter`, error);
|
|
71
|
+
this.callbacks.onFallbackFailure?.();
|
|
72
|
+
this.disable();
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.FallbackCoordinator = FallbackCoordinator;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IngestPayload } from '../models';
|
|
2
|
+
import { FsWriter } from '../writer';
|
|
3
|
+
import type { LoggerInterface } from '../utils';
|
|
4
|
+
import type { InternalReporterInterface } from './reporter-interface';
|
|
5
|
+
export declare class FileReporter implements InternalReporterInterface {
|
|
6
|
+
private readonly writer;
|
|
7
|
+
private readonly logger;
|
|
8
|
+
constructor(logger: LoggerInterface, writer: FsWriter);
|
|
9
|
+
publishPayload(payload: IngestPayload): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FileReporter = void 0;
|
|
4
|
+
class FileReporter {
|
|
5
|
+
writer;
|
|
6
|
+
logger;
|
|
7
|
+
constructor(logger, writer) {
|
|
8
|
+
this.logger = logger;
|
|
9
|
+
this.writer = writer;
|
|
10
|
+
}
|
|
11
|
+
async publishPayload(payload) {
|
|
12
|
+
const path = this.writer.writePayload(payload);
|
|
13
|
+
this.logger.log(`Wrote ingest payload to ${path}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.FileReporter = FileReporter;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FallbackCoordinator = exports.FileReporter = exports.IngestReporter = void 0;
|
|
4
|
+
var ingest_reporter_1 = require("./ingest-reporter");
|
|
5
|
+
Object.defineProperty(exports, "IngestReporter", { enumerable: true, get: function () { return ingest_reporter_1.IngestReporter; } });
|
|
6
|
+
var file_reporter_1 = require("./file-reporter");
|
|
7
|
+
Object.defineProperty(exports, "FileReporter", { enumerable: true, get: function () { return file_reporter_1.FileReporter; } });
|
|
8
|
+
var fallback_coordinator_1 = require("./fallback-coordinator");
|
|
9
|
+
Object.defineProperty(exports, "FallbackCoordinator", { enumerable: true, get: function () { return fallback_coordinator_1.FallbackCoordinator; } });
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IngestClient } from '../client';
|
|
2
|
+
import type { IngestPayload } from '../models';
|
|
3
|
+
import type { LoggerInterface } from '../utils';
|
|
4
|
+
import type { InternalReporterInterface } from './reporter-interface';
|
|
5
|
+
export declare class IngestReporter implements InternalReporterInterface {
|
|
6
|
+
private readonly client;
|
|
7
|
+
constructor(logger: LoggerInterface, client: IngestClient);
|
|
8
|
+
publishPayload(payload: IngestPayload): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IngestReporter = void 0;
|
|
4
|
+
class IngestReporter {
|
|
5
|
+
client;
|
|
6
|
+
constructor(logger, client) {
|
|
7
|
+
this.client = client;
|
|
8
|
+
void logger;
|
|
9
|
+
}
|
|
10
|
+
async publishPayload(payload) {
|
|
11
|
+
await this.client.send(payload);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.IngestReporter = IngestReporter;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { DisabledException } from './disabled-exception';
|
|
2
|
+
export { Logger, type LoggerInterface } from './logger';
|
|
3
|
+
export { maskToken, sanitizeOptionsForLog } from './token-masker';
|
|
4
|
+
export { extractIssueKeys, firstIssueKey, projectKeyFromIssueKey, } from './issue-keys';
|
|
5
|
+
export { uploadAttachmentForQa, EnvAttachEnum, type UploadAttachParams, type UploadAttachOutcome, } from './upload-attachment';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EnvAttachEnum = exports.uploadAttachmentForQa = exports.projectKeyFromIssueKey = exports.firstIssueKey = exports.extractIssueKeys = exports.sanitizeOptionsForLog = exports.maskToken = exports.Logger = exports.DisabledException = void 0;
|
|
4
|
+
var disabled_exception_1 = require("./disabled-exception");
|
|
5
|
+
Object.defineProperty(exports, "DisabledException", { enumerable: true, get: function () { return disabled_exception_1.DisabledException; } });
|
|
6
|
+
var logger_1 = require("./logger");
|
|
7
|
+
Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return logger_1.Logger; } });
|
|
8
|
+
var token_masker_1 = require("./token-masker");
|
|
9
|
+
Object.defineProperty(exports, "maskToken", { enumerable: true, get: function () { return token_masker_1.maskToken; } });
|
|
10
|
+
Object.defineProperty(exports, "sanitizeOptionsForLog", { enumerable: true, get: function () { return token_masker_1.sanitizeOptionsForLog; } });
|
|
11
|
+
var issue_keys_1 = require("./issue-keys");
|
|
12
|
+
Object.defineProperty(exports, "extractIssueKeys", { enumerable: true, get: function () { return issue_keys_1.extractIssueKeys; } });
|
|
13
|
+
Object.defineProperty(exports, "firstIssueKey", { enumerable: true, get: function () { return issue_keys_1.firstIssueKey; } });
|
|
14
|
+
Object.defineProperty(exports, "projectKeyFromIssueKey", { enumerable: true, get: function () { return issue_keys_1.projectKeyFromIssueKey; } });
|
|
15
|
+
var upload_attachment_1 = require("./upload-attachment");
|
|
16
|
+
Object.defineProperty(exports, "uploadAttachmentForQa", { enumerable: true, get: function () { return upload_attachment_1.uploadAttachmentForQa; } });
|
|
17
|
+
Object.defineProperty(exports, "EnvAttachEnum", { enumerable: true, get: function () { return upload_attachment_1.EnvAttachEnum; } });
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract Jira issue keys from titles / tags (FR43) — shared with reporters for attach target.
|
|
3
|
+
*/
|
|
4
|
+
export declare function extractIssueKeys(...sources: Array<string | null | undefined>): string[];
|
|
5
|
+
export declare function firstIssueKey(...sources: Array<string | null | undefined>): string | null;
|
|
6
|
+
/** Project key prefix from AUTH-101 → AUTH. */
|
|
7
|
+
export declare function projectKeyFromIssueKey(issueKey: string): string | null;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractIssueKeys = extractIssueKeys;
|
|
4
|
+
exports.firstIssueKey = firstIssueKey;
|
|
5
|
+
exports.projectKeyFromIssueKey = projectKeyFromIssueKey;
|
|
6
|
+
const ISSUE_KEY_RE = /\b([A-Z][A-Z0-9]+-\d+)\b/g;
|
|
7
|
+
/**
|
|
8
|
+
* Extract Jira issue keys from titles / tags (FR43) — shared with reporters for attach target.
|
|
9
|
+
*/
|
|
10
|
+
function extractIssueKeys(...sources) {
|
|
11
|
+
const seen = new Set();
|
|
12
|
+
const keys = [];
|
|
13
|
+
for (const source of sources) {
|
|
14
|
+
if (!source)
|
|
15
|
+
continue;
|
|
16
|
+
for (const match of source.matchAll(ISSUE_KEY_RE)) {
|
|
17
|
+
const key = match[1];
|
|
18
|
+
if (key && !seen.has(key)) {
|
|
19
|
+
seen.add(key);
|
|
20
|
+
keys.push(key);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return keys;
|
|
25
|
+
}
|
|
26
|
+
function firstIssueKey(...sources) {
|
|
27
|
+
return extractIssueKeys(...sources)[0] ?? null;
|
|
28
|
+
}
|
|
29
|
+
/** Project key prefix from AUTH-101 → AUTH. */
|
|
30
|
+
function projectKeyFromIssueKey(issueKey) {
|
|
31
|
+
const m = /^([A-Z][A-Z0-9]+)-\d+$/.exec(issueKey.trim().toUpperCase());
|
|
32
|
+
return m?.[1] ?? null;
|
|
33
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface LoggerInterface {
|
|
2
|
+
log(message: string): void;
|
|
3
|
+
logError(message: string, error?: unknown): void;
|
|
4
|
+
logDebug(message: string): void;
|
|
5
|
+
}
|
|
6
|
+
export declare class Logger implements LoggerInterface {
|
|
7
|
+
private readonly debugEnabled;
|
|
8
|
+
constructor(debugEnabled?: boolean);
|
|
9
|
+
log(message: string): void;
|
|
10
|
+
logError(message: string, error?: unknown): void;
|
|
11
|
+
logDebug(message: string): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Logger = void 0;
|
|
4
|
+
class Logger {
|
|
5
|
+
debugEnabled;
|
|
6
|
+
constructor(debugEnabled = false) {
|
|
7
|
+
this.debugEnabled = debugEnabled;
|
|
8
|
+
}
|
|
9
|
+
log(message) {
|
|
10
|
+
console.log(`[INFO] qanalyzer: ${message}`);
|
|
11
|
+
}
|
|
12
|
+
logError(message, error) {
|
|
13
|
+
console.error(`[ERROR] qanalyzer: ${message}`, error ?? '');
|
|
14
|
+
}
|
|
15
|
+
logDebug(message) {
|
|
16
|
+
if (!this.debugEnabled)
|
|
17
|
+
return;
|
|
18
|
+
console.debug(`[DEBUG] qanalyzer: ${message}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.Logger = Logger;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.maskToken = maskToken;
|
|
4
|
+
exports.sanitizeOptionsForLog = sanitizeOptionsForLog;
|
|
5
|
+
function maskToken(token) {
|
|
6
|
+
if (token.length <= 7) {
|
|
7
|
+
return '*'.repeat(token.length);
|
|
8
|
+
}
|
|
9
|
+
return `${token.slice(0, 3)}****${token.slice(-4)}`;
|
|
10
|
+
}
|
|
11
|
+
function sanitizeOptionsForLog(options) {
|
|
12
|
+
const sanitized = JSON.parse(JSON.stringify(options));
|
|
13
|
+
if (sanitized.ingest?.token) {
|
|
14
|
+
sanitized.ingest.token = maskToken(sanitized.ingest.token);
|
|
15
|
+
}
|
|
16
|
+
return sanitized;
|
|
17
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { QaMetaAttachmentWire } from '../models/meta-qa';
|
|
2
|
+
export declare const EnvAttachEnum: {
|
|
3
|
+
/** @deprecated Prefer QANALYZER_INGEST_URL — attach uses the shared ingest webtrigger. */
|
|
4
|
+
readonly url: "QANALYZER_ATTACH_URL";
|
|
5
|
+
readonly maxBytes: "QANALYZER_ATTACH_MAX_BYTES";
|
|
6
|
+
};
|
|
7
|
+
export type UploadAttachParams = {
|
|
8
|
+
/** Explicit issue key override. */
|
|
9
|
+
issueKey?: string;
|
|
10
|
+
/** Sources used to discover issue key (test title, tags, …). */
|
|
11
|
+
issueKeySources?: Array<string | null | undefined>;
|
|
12
|
+
projectKey?: string;
|
|
13
|
+
fileName?: string;
|
|
14
|
+
mimeType?: string;
|
|
15
|
+
content?: Buffer | Uint8Array | string;
|
|
16
|
+
/** Read file from disk when content omitted. */
|
|
17
|
+
path?: string;
|
|
18
|
+
attachUrl?: string;
|
|
19
|
+
token?: string;
|
|
20
|
+
maxBytes?: number;
|
|
21
|
+
};
|
|
22
|
+
export type UploadAttachOutcome = {
|
|
23
|
+
uploaded: true;
|
|
24
|
+
attachment: QaMetaAttachmentWire;
|
|
25
|
+
issueKey: string;
|
|
26
|
+
} | {
|
|
27
|
+
uploaded: false;
|
|
28
|
+
attachment: QaMetaAttachmentWire;
|
|
29
|
+
reason: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Attempt Forge→Jira upload. On missing config/key/content, returns metadata-only (never throws
|
|
33
|
+
* unless you want callers to catch — this helper swallows upload errors into `uploaded: false`).
|
|
34
|
+
*/
|
|
35
|
+
export declare function uploadAttachmentForQa(params: UploadAttachParams): Promise<UploadAttachOutcome>;
|