@mergifyio/ci-core 0.2.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 +17 -0
- package/dist/index.cjs +520 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +183 -0
- package/dist/index.d.mts +183 -0
- package/dist/index.mjs +502 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +51 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { Attributes, Span, Tracer } from "@opentelemetry/api";
|
|
2
|
+
import { Resource } from "@opentelemetry/resources";
|
|
3
|
+
import { BasicTracerProvider, ReadableSpan, SpanExporter, SpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
4
|
+
|
|
5
|
+
//#region src/flaky-detection.d.ts
|
|
6
|
+
type FlakyDetectionContext = {
|
|
7
|
+
budget_ratio_for_new_tests: number;
|
|
8
|
+
budget_ratio_for_unhealthy_tests: number;
|
|
9
|
+
existing_test_names: string[];
|
|
10
|
+
existing_tests_mean_duration_ms: number;
|
|
11
|
+
unhealthy_test_names: string[];
|
|
12
|
+
max_test_execution_count: number;
|
|
13
|
+
max_test_name_length: number;
|
|
14
|
+
min_budget_duration_ms: number;
|
|
15
|
+
min_test_execution_count: number;
|
|
16
|
+
};
|
|
17
|
+
type FlakyDetectionMode = 'new' | 'unhealthy';
|
|
18
|
+
type FlakyDetectionConfig = {
|
|
19
|
+
apiUrl: string;
|
|
20
|
+
token: string;
|
|
21
|
+
repoName: string;
|
|
22
|
+
};
|
|
23
|
+
declare function fetchFlakyDetectionContext(config: FlakyDetectionConfig, logger: (msg: string) => void): Promise<FlakyDetectionContext | null>;
|
|
24
|
+
declare class FlakyDetector {
|
|
25
|
+
private context;
|
|
26
|
+
private mode;
|
|
27
|
+
private candidates;
|
|
28
|
+
private existingTestsInSession;
|
|
29
|
+
private budgetMs;
|
|
30
|
+
private perTestDeadlineMs;
|
|
31
|
+
private testMetrics;
|
|
32
|
+
private tooSlowTests;
|
|
33
|
+
constructor(context: FlakyDetectionContext, mode: FlakyDetectionMode, allTestNames: string[]);
|
|
34
|
+
isCandidate(testName: string): boolean;
|
|
35
|
+
/** Calculate max repeats for a candidate test. Call after first execution to use actual duration. */
|
|
36
|
+
getMaxRepeats(testName: string, initialDurationMs: number): number;
|
|
37
|
+
recordOutcome(testName: string, outcome: 'pass' | 'fail'): void;
|
|
38
|
+
isFlaky(testName: string): boolean;
|
|
39
|
+
getRerunCount(testName: string): number;
|
|
40
|
+
isTooSlow(testName: string): boolean;
|
|
41
|
+
/** Get summary data for the terminal report. */
|
|
42
|
+
getSummary(): {
|
|
43
|
+
mode: FlakyDetectionMode;
|
|
44
|
+
budgetMs: number;
|
|
45
|
+
candidateCount: number;
|
|
46
|
+
rerunTests: Array<{
|
|
47
|
+
name: string;
|
|
48
|
+
rerunCount: number;
|
|
49
|
+
flaky: boolean;
|
|
50
|
+
outcomes: string[];
|
|
51
|
+
}>;
|
|
52
|
+
tooSlowTests: string[];
|
|
53
|
+
};
|
|
54
|
+
private getOrCreateMetrics;
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/quarantine.d.ts
|
|
58
|
+
interface QuarantineConfig {
|
|
59
|
+
apiUrl: string;
|
|
60
|
+
token: string;
|
|
61
|
+
repoName: string;
|
|
62
|
+
branch: string;
|
|
63
|
+
}
|
|
64
|
+
declare function fetchQuarantineList(config: QuarantineConfig, logger: (msg: string) => void): Promise<Set<string>>;
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/resources/index.d.ts
|
|
67
|
+
declare function detectResources(frameworkAttributes: Attributes, testRunId: string): Resource;
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/tracing.d.ts
|
|
70
|
+
interface TracingConfig {
|
|
71
|
+
token: string | undefined;
|
|
72
|
+
repoName: string | undefined;
|
|
73
|
+
apiUrl: string;
|
|
74
|
+
testRunId: string;
|
|
75
|
+
frameworkAttributes: Attributes;
|
|
76
|
+
tracerName: string;
|
|
77
|
+
/** Injected exporter — bypasses CI and token checks. */
|
|
78
|
+
exporter?: SpanExporter;
|
|
79
|
+
}
|
|
80
|
+
interface TracingContext {
|
|
81
|
+
tracer: Tracer;
|
|
82
|
+
tracerProvider: BasicTracerProvider;
|
|
83
|
+
exporter: SpanExporter;
|
|
84
|
+
resource: Resource;
|
|
85
|
+
/** Whether the provider should be shut down on test run end. */
|
|
86
|
+
ownsExporter: boolean;
|
|
87
|
+
}
|
|
88
|
+
declare class SynchronousBatchSpanProcessor implements SpanProcessor {
|
|
89
|
+
private exporter;
|
|
90
|
+
private queue;
|
|
91
|
+
constructor(exporter: SpanExporter);
|
|
92
|
+
onStart(): void;
|
|
93
|
+
onEnd(span: ReadableSpan): void;
|
|
94
|
+
forceFlush(): Promise<void>;
|
|
95
|
+
shutdown(): Promise<void>;
|
|
96
|
+
}
|
|
97
|
+
declare function createTracing(config: TracingConfig): TracingContext | null;
|
|
98
|
+
//#endregion
|
|
99
|
+
//#region src/types.d.ts
|
|
100
|
+
interface TestCaseError {
|
|
101
|
+
type: string;
|
|
102
|
+
message: string;
|
|
103
|
+
stacktrace: string;
|
|
104
|
+
}
|
|
105
|
+
interface TestCaseFlakyDetection {
|
|
106
|
+
new: boolean;
|
|
107
|
+
flaky: boolean;
|
|
108
|
+
rerunCount: number;
|
|
109
|
+
}
|
|
110
|
+
interface TestCaseResult {
|
|
111
|
+
/** Relative file path (e.g. Vitest TestModule.relativeModuleId) */
|
|
112
|
+
filepath: string;
|
|
113
|
+
/** Absolute file path (e.g. Vitest TestModule.moduleId) */
|
|
114
|
+
absoluteFilepath: string;
|
|
115
|
+
/** Test name (e.g. Vitest TestCase.name) */
|
|
116
|
+
function: string;
|
|
117
|
+
/** Line number in the file (Vitest requires includeTaskLocation) */
|
|
118
|
+
lineno: number;
|
|
119
|
+
/** Parent suite chain (e.g. derived from Vitest fullName) */
|
|
120
|
+
namespace: string;
|
|
121
|
+
scope: 'case';
|
|
122
|
+
status: 'passed' | 'failed' | 'skipped';
|
|
123
|
+
error?: TestCaseError;
|
|
124
|
+
/** Duration in ms */
|
|
125
|
+
duration: number;
|
|
126
|
+
/** Start time in ms */
|
|
127
|
+
startTime: number;
|
|
128
|
+
/** Number of retries */
|
|
129
|
+
retryCount: number;
|
|
130
|
+
/** Whether the test passed on a retry (native framework flaky) */
|
|
131
|
+
flaky: boolean;
|
|
132
|
+
/** Framework sub-identity (Playwright project name). Optional. */
|
|
133
|
+
project?: string;
|
|
134
|
+
/** Whether the test is quarantined. Set by Vitest runner when the quarantine feature is active. */
|
|
135
|
+
quarantined?: boolean;
|
|
136
|
+
/** Flaky-detection metadata. Set by Vitest runner when flaky detection is active. */
|
|
137
|
+
flakyDetection?: TestCaseFlakyDetection;
|
|
138
|
+
}
|
|
139
|
+
interface TestRunSession {
|
|
140
|
+
/** 16-char hex ID (8 random bytes), matching Mergify CI Insights API format */
|
|
141
|
+
testRunId: string;
|
|
142
|
+
scope: 'session';
|
|
143
|
+
startTime: number;
|
|
144
|
+
endTime?: number;
|
|
145
|
+
status: 'passed' | 'failed' | 'interrupted';
|
|
146
|
+
testCases: TestCaseResult[];
|
|
147
|
+
}
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region src/spans.d.ts
|
|
150
|
+
declare function startSessionSpan(tracing: TracingContext, name: string): Span;
|
|
151
|
+
declare function endSessionSpan(tracing: TracingContext, sessionSpan: Span, reason: 'passed' | 'failed' | 'interrupted'): Promise<void>;
|
|
152
|
+
declare function emitTestCaseSpan(tracer: Tracer, sessionSpan: Span, result: TestCaseResult): void;
|
|
153
|
+
//#endregion
|
|
154
|
+
//#region src/utils.d.ts
|
|
155
|
+
type CIProvider = 'github_actions' | 'jenkins' | 'circleci' | 'buildkite';
|
|
156
|
+
/**
|
|
157
|
+
* Generate a 16-character hex test run ID (8 random bytes).
|
|
158
|
+
*/
|
|
159
|
+
declare function generateTestRunId(): string;
|
|
160
|
+
/** Convert a string to a boolean. */
|
|
161
|
+
declare function strtobool(value: string): boolean;
|
|
162
|
+
declare function envToBool(value: string | undefined, fallback: boolean): boolean;
|
|
163
|
+
/** Check if running in a CI environment. */
|
|
164
|
+
declare function isInCI(): boolean;
|
|
165
|
+
/** Detect the current CI provider from environment variables. */
|
|
166
|
+
declare function getCIProvider(): CIProvider | null;
|
|
167
|
+
/** Execute a git command and return trimmed stdout, or null on failure. */
|
|
168
|
+
declare function git(...args: string[]): string | null;
|
|
169
|
+
/** Split an "owner/repo" string into parts. */
|
|
170
|
+
declare function splitRepoName(fullName: string): {
|
|
171
|
+
owner: string;
|
|
172
|
+
repo: string;
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Resolve the repository name ("owner/repo") from env vars or the git remote.
|
|
176
|
+
* Checks GITHUB_REPOSITORY, then GIT_URL, then falls back to `git config`.
|
|
177
|
+
*/
|
|
178
|
+
declare function getRepoName(): string | undefined;
|
|
179
|
+
/** Parse a repository name from a git remote URL (SSH or HTTPS). */
|
|
180
|
+
declare function getRepositoryNameFromUrl(url: string): string | null;
|
|
181
|
+
//#endregion
|
|
182
|
+
export { type CIProvider, type FlakyDetectionConfig, type FlakyDetectionContext, type FlakyDetectionMode, FlakyDetector, type QuarantineConfig, SynchronousBatchSpanProcessor, type TestCaseError, type TestCaseFlakyDetection, type TestCaseResult, type TestRunSession, type TracingConfig, type TracingContext, createTracing, detectResources, emitTestCaseSpan, endSessionSpan, envToBool, fetchFlakyDetectionContext, fetchQuarantineList, generateTestRunId, getCIProvider, getRepoName, getRepositoryNameFromUrl, git, isInCI, splitRepoName, startSessionSpan, strtobool };
|
|
183
|
+
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { Resource } from "@opentelemetry/resources";
|
|
2
|
+
import { Attributes, Span, Tracer } from "@opentelemetry/api";
|
|
3
|
+
import { BasicTracerProvider, ReadableSpan, SpanExporter, SpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
4
|
+
|
|
5
|
+
//#region src/flaky-detection.d.ts
|
|
6
|
+
type FlakyDetectionContext = {
|
|
7
|
+
budget_ratio_for_new_tests: number;
|
|
8
|
+
budget_ratio_for_unhealthy_tests: number;
|
|
9
|
+
existing_test_names: string[];
|
|
10
|
+
existing_tests_mean_duration_ms: number;
|
|
11
|
+
unhealthy_test_names: string[];
|
|
12
|
+
max_test_execution_count: number;
|
|
13
|
+
max_test_name_length: number;
|
|
14
|
+
min_budget_duration_ms: number;
|
|
15
|
+
min_test_execution_count: number;
|
|
16
|
+
};
|
|
17
|
+
type FlakyDetectionMode = 'new' | 'unhealthy';
|
|
18
|
+
type FlakyDetectionConfig = {
|
|
19
|
+
apiUrl: string;
|
|
20
|
+
token: string;
|
|
21
|
+
repoName: string;
|
|
22
|
+
};
|
|
23
|
+
declare function fetchFlakyDetectionContext(config: FlakyDetectionConfig, logger: (msg: string) => void): Promise<FlakyDetectionContext | null>;
|
|
24
|
+
declare class FlakyDetector {
|
|
25
|
+
private context;
|
|
26
|
+
private mode;
|
|
27
|
+
private candidates;
|
|
28
|
+
private existingTestsInSession;
|
|
29
|
+
private budgetMs;
|
|
30
|
+
private perTestDeadlineMs;
|
|
31
|
+
private testMetrics;
|
|
32
|
+
private tooSlowTests;
|
|
33
|
+
constructor(context: FlakyDetectionContext, mode: FlakyDetectionMode, allTestNames: string[]);
|
|
34
|
+
isCandidate(testName: string): boolean;
|
|
35
|
+
/** Calculate max repeats for a candidate test. Call after first execution to use actual duration. */
|
|
36
|
+
getMaxRepeats(testName: string, initialDurationMs: number): number;
|
|
37
|
+
recordOutcome(testName: string, outcome: 'pass' | 'fail'): void;
|
|
38
|
+
isFlaky(testName: string): boolean;
|
|
39
|
+
getRerunCount(testName: string): number;
|
|
40
|
+
isTooSlow(testName: string): boolean;
|
|
41
|
+
/** Get summary data for the terminal report. */
|
|
42
|
+
getSummary(): {
|
|
43
|
+
mode: FlakyDetectionMode;
|
|
44
|
+
budgetMs: number;
|
|
45
|
+
candidateCount: number;
|
|
46
|
+
rerunTests: Array<{
|
|
47
|
+
name: string;
|
|
48
|
+
rerunCount: number;
|
|
49
|
+
flaky: boolean;
|
|
50
|
+
outcomes: string[];
|
|
51
|
+
}>;
|
|
52
|
+
tooSlowTests: string[];
|
|
53
|
+
};
|
|
54
|
+
private getOrCreateMetrics;
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/quarantine.d.ts
|
|
58
|
+
interface QuarantineConfig {
|
|
59
|
+
apiUrl: string;
|
|
60
|
+
token: string;
|
|
61
|
+
repoName: string;
|
|
62
|
+
branch: string;
|
|
63
|
+
}
|
|
64
|
+
declare function fetchQuarantineList(config: QuarantineConfig, logger: (msg: string) => void): Promise<Set<string>>;
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/resources/index.d.ts
|
|
67
|
+
declare function detectResources(frameworkAttributes: Attributes, testRunId: string): Resource;
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/tracing.d.ts
|
|
70
|
+
interface TracingConfig {
|
|
71
|
+
token: string | undefined;
|
|
72
|
+
repoName: string | undefined;
|
|
73
|
+
apiUrl: string;
|
|
74
|
+
testRunId: string;
|
|
75
|
+
frameworkAttributes: Attributes;
|
|
76
|
+
tracerName: string;
|
|
77
|
+
/** Injected exporter — bypasses CI and token checks. */
|
|
78
|
+
exporter?: SpanExporter;
|
|
79
|
+
}
|
|
80
|
+
interface TracingContext {
|
|
81
|
+
tracer: Tracer;
|
|
82
|
+
tracerProvider: BasicTracerProvider;
|
|
83
|
+
exporter: SpanExporter;
|
|
84
|
+
resource: Resource;
|
|
85
|
+
/** Whether the provider should be shut down on test run end. */
|
|
86
|
+
ownsExporter: boolean;
|
|
87
|
+
}
|
|
88
|
+
declare class SynchronousBatchSpanProcessor implements SpanProcessor {
|
|
89
|
+
private exporter;
|
|
90
|
+
private queue;
|
|
91
|
+
constructor(exporter: SpanExporter);
|
|
92
|
+
onStart(): void;
|
|
93
|
+
onEnd(span: ReadableSpan): void;
|
|
94
|
+
forceFlush(): Promise<void>;
|
|
95
|
+
shutdown(): Promise<void>;
|
|
96
|
+
}
|
|
97
|
+
declare function createTracing(config: TracingConfig): TracingContext | null;
|
|
98
|
+
//#endregion
|
|
99
|
+
//#region src/types.d.ts
|
|
100
|
+
interface TestCaseError {
|
|
101
|
+
type: string;
|
|
102
|
+
message: string;
|
|
103
|
+
stacktrace: string;
|
|
104
|
+
}
|
|
105
|
+
interface TestCaseFlakyDetection {
|
|
106
|
+
new: boolean;
|
|
107
|
+
flaky: boolean;
|
|
108
|
+
rerunCount: number;
|
|
109
|
+
}
|
|
110
|
+
interface TestCaseResult {
|
|
111
|
+
/** Relative file path (e.g. Vitest TestModule.relativeModuleId) */
|
|
112
|
+
filepath: string;
|
|
113
|
+
/** Absolute file path (e.g. Vitest TestModule.moduleId) */
|
|
114
|
+
absoluteFilepath: string;
|
|
115
|
+
/** Test name (e.g. Vitest TestCase.name) */
|
|
116
|
+
function: string;
|
|
117
|
+
/** Line number in the file (Vitest requires includeTaskLocation) */
|
|
118
|
+
lineno: number;
|
|
119
|
+
/** Parent suite chain (e.g. derived from Vitest fullName) */
|
|
120
|
+
namespace: string;
|
|
121
|
+
scope: 'case';
|
|
122
|
+
status: 'passed' | 'failed' | 'skipped';
|
|
123
|
+
error?: TestCaseError;
|
|
124
|
+
/** Duration in ms */
|
|
125
|
+
duration: number;
|
|
126
|
+
/** Start time in ms */
|
|
127
|
+
startTime: number;
|
|
128
|
+
/** Number of retries */
|
|
129
|
+
retryCount: number;
|
|
130
|
+
/** Whether the test passed on a retry (native framework flaky) */
|
|
131
|
+
flaky: boolean;
|
|
132
|
+
/** Framework sub-identity (Playwright project name). Optional. */
|
|
133
|
+
project?: string;
|
|
134
|
+
/** Whether the test is quarantined. Set by Vitest runner when the quarantine feature is active. */
|
|
135
|
+
quarantined?: boolean;
|
|
136
|
+
/** Flaky-detection metadata. Set by Vitest runner when flaky detection is active. */
|
|
137
|
+
flakyDetection?: TestCaseFlakyDetection;
|
|
138
|
+
}
|
|
139
|
+
interface TestRunSession {
|
|
140
|
+
/** 16-char hex ID (8 random bytes), matching Mergify CI Insights API format */
|
|
141
|
+
testRunId: string;
|
|
142
|
+
scope: 'session';
|
|
143
|
+
startTime: number;
|
|
144
|
+
endTime?: number;
|
|
145
|
+
status: 'passed' | 'failed' | 'interrupted';
|
|
146
|
+
testCases: TestCaseResult[];
|
|
147
|
+
}
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region src/spans.d.ts
|
|
150
|
+
declare function startSessionSpan(tracing: TracingContext, name: string): Span;
|
|
151
|
+
declare function endSessionSpan(tracing: TracingContext, sessionSpan: Span, reason: 'passed' | 'failed' | 'interrupted'): Promise<void>;
|
|
152
|
+
declare function emitTestCaseSpan(tracer: Tracer, sessionSpan: Span, result: TestCaseResult): void;
|
|
153
|
+
//#endregion
|
|
154
|
+
//#region src/utils.d.ts
|
|
155
|
+
type CIProvider = 'github_actions' | 'jenkins' | 'circleci' | 'buildkite';
|
|
156
|
+
/**
|
|
157
|
+
* Generate a 16-character hex test run ID (8 random bytes).
|
|
158
|
+
*/
|
|
159
|
+
declare function generateTestRunId(): string;
|
|
160
|
+
/** Convert a string to a boolean. */
|
|
161
|
+
declare function strtobool(value: string): boolean;
|
|
162
|
+
declare function envToBool(value: string | undefined, fallback: boolean): boolean;
|
|
163
|
+
/** Check if running in a CI environment. */
|
|
164
|
+
declare function isInCI(): boolean;
|
|
165
|
+
/** Detect the current CI provider from environment variables. */
|
|
166
|
+
declare function getCIProvider(): CIProvider | null;
|
|
167
|
+
/** Execute a git command and return trimmed stdout, or null on failure. */
|
|
168
|
+
declare function git(...args: string[]): string | null;
|
|
169
|
+
/** Split an "owner/repo" string into parts. */
|
|
170
|
+
declare function splitRepoName(fullName: string): {
|
|
171
|
+
owner: string;
|
|
172
|
+
repo: string;
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Resolve the repository name ("owner/repo") from env vars or the git remote.
|
|
176
|
+
* Checks GITHUB_REPOSITORY, then GIT_URL, then falls back to `git config`.
|
|
177
|
+
*/
|
|
178
|
+
declare function getRepoName(): string | undefined;
|
|
179
|
+
/** Parse a repository name from a git remote URL (SSH or HTTPS). */
|
|
180
|
+
declare function getRepositoryNameFromUrl(url: string): string | null;
|
|
181
|
+
//#endregion
|
|
182
|
+
export { type CIProvider, type FlakyDetectionConfig, type FlakyDetectionContext, type FlakyDetectionMode, FlakyDetector, type QuarantineConfig, SynchronousBatchSpanProcessor, type TestCaseError, type TestCaseFlakyDetection, type TestCaseResult, type TestRunSession, type TracingConfig, type TracingContext, createTracing, detectResources, emitTestCaseSpan, endSessionSpan, envToBool, fetchFlakyDetectionContext, fetchQuarantineList, generateTestRunId, getCIProvider, getRepoName, getRepositoryNameFromUrl, git, isInCI, splitRepoName, startSessionSpan, strtobool };
|
|
183
|
+
//# sourceMappingURL=index.d.mts.map
|