@data_engine_labs/data_engine_sdk 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 +97 -0
- package/dist/index.cjs +354 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +322 -0
- package/dist/index.js.map +1 -0
- package/dist/playwright/reporter.cjs +338 -0
- package/dist/playwright/reporter.cjs.map +1 -0
- package/dist/playwright/reporter.d.cts +2 -0
- package/dist/playwright/reporter.d.ts +2 -0
- package/dist/playwright/reporter.js +317 -0
- package/dist/playwright/reporter.js.map +1 -0
- package/dist/reporter-DZCr9FGW.d.cts +105 -0
- package/dist/reporter-DZCr9FGW.d.ts +105 -0
- package/package.json +73 -0
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# @data_engine_labs/data_engine_sdk
|
|
2
|
+
|
|
3
|
+
SDK JS/TS para capturar metricas de tests y enviarlas al portal **Data Engine**. En v1 soporta **Playwright** como reporter drop-in, mas una API manual para casos avanzados.
|
|
4
|
+
|
|
5
|
+
## Instalacion
|
|
6
|
+
|
|
7
|
+
El paquete se publica en el **npm publico** (`registry.npmjs.org`). No requiere token ni `.npmrc`.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add -D @data_engine_labs/data_engine_sdk
|
|
11
|
+
# o
|
|
12
|
+
npm i -D @data_engine_labs/data_engine_sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Uso con Playwright (recomendado)
|
|
16
|
+
|
|
17
|
+
Anade el reporter a tu `playwright.config.ts`:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { defineConfig } from "@playwright/test";
|
|
21
|
+
|
|
22
|
+
export default defineConfig({
|
|
23
|
+
reporter: [
|
|
24
|
+
["list"],
|
|
25
|
+
["@data_engine_labs/data_engine_sdk/playwright"],
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Configura via variables de entorno (tipico en CI):
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
export DATA_ENGINE_API_KEY="dek_...."
|
|
34
|
+
export DATA_ENGINE_BASE_URL="https://portal.example.com"
|
|
35
|
+
export DATA_ENGINE_ENVIRONMENT="staging"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
El reporter detecta el contexto del pipeline (branch, commit, URL del run, quien lo dispar) automaticamente en GitHub Actions, Azure Pipelines y GitLab CI.
|
|
39
|
+
|
|
40
|
+
## Variables de entorno
|
|
41
|
+
|
|
42
|
+
| Variable | Requerida | Uso |
|
|
43
|
+
| --- | --- | --- |
|
|
44
|
+
| `DATA_ENGINE_API_KEY` | si | API key `dek_...` del proyecto |
|
|
45
|
+
| `DATA_ENGINE_BASE_URL` | si | URL base del portal |
|
|
46
|
+
| `DATA_ENGINE_ENVIRONMENT` | si | Nombre del ambiente (staging, prod, ...) |
|
|
47
|
+
| `DATA_ENGINE_BRANCH` | no | Override manual de branch |
|
|
48
|
+
| `DATA_ENGINE_COMMIT_SHA` | no | Override manual de commit |
|
|
49
|
+
| `DATA_ENGINE_TRIGGERED_BY` | no | Override manual de trigger |
|
|
50
|
+
| `DATA_ENGINE_PIPELINE_RUN_URL` | no | Override manual de URL |
|
|
51
|
+
| `DATA_ENGINE_STRICT` | no | `"true"` para fallar el job si el submit falla |
|
|
52
|
+
| `DATA_ENGINE_DISABLE` | no | `"true"` para desactivar el reporter |
|
|
53
|
+
|
|
54
|
+
**Precedencia por campo:** argumento constructor > env var > detector CI > undefined.
|
|
55
|
+
|
|
56
|
+
## Uso manual (API programatica)
|
|
57
|
+
|
|
58
|
+
Para frameworks no soportados nativamente, o para reportar corridas ad-hoc:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { createClient, detectPipeline } from "@data_engine_labs/data_engine_sdk";
|
|
62
|
+
import { randomUUID } from "node:crypto";
|
|
63
|
+
|
|
64
|
+
const client = createClient({
|
|
65
|
+
apiKey: process.env.DATA_ENGINE_API_KEY!,
|
|
66
|
+
baseUrl: process.env.DATA_ENGINE_BASE_URL!,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const pipeline = detectPipeline();
|
|
70
|
+
|
|
71
|
+
await client.submitRun({
|
|
72
|
+
runId: randomUUID(),
|
|
73
|
+
framework: "PLAYWRIGHT",
|
|
74
|
+
environment: "staging",
|
|
75
|
+
branch: pipeline.branch ?? "main",
|
|
76
|
+
commitSha: pipeline.commitSha,
|
|
77
|
+
triggeredBy: pipeline.triggeredBy,
|
|
78
|
+
pipelineRunUrl: pipeline.pipelineRunUrl,
|
|
79
|
+
startedAt: new Date(Date.now() - 60_000).toISOString(),
|
|
80
|
+
finishedAt: new Date().toISOString(),
|
|
81
|
+
results: [
|
|
82
|
+
{ name: "sample test", suite: "example.spec.ts", status: "PASSED", durationMs: 100, retries: 0, tags: [] },
|
|
83
|
+
],
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Semantica de FLAKY
|
|
88
|
+
|
|
89
|
+
Un test que fallo y despues paso en un retry se reporta con `status: "FLAKY"` a nivel individual, pero cuenta como **PASSED** en el rollup de la corrida (`overallStatus`, `passed`). Esto permite trazabilidad de tests inestables sin marcar toda la corrida como fallida.
|
|
90
|
+
|
|
91
|
+
## Fail-open por defecto
|
|
92
|
+
|
|
93
|
+
Si el submit al portal falla (red, 500, timeout), la SDK loguea un `console.warn` pero **no rompe** el CI job. Setea `DATA_ENGINE_STRICT=true` para invertir este comportamiento.
|
|
94
|
+
|
|
95
|
+
## Idempotencia
|
|
96
|
+
|
|
97
|
+
Cada corrida se envia con un `runId` unico (UUID). Si el mismo `runId` se reenvia (por ejemplo por un reintento de CI), el endpoint responde `200` con el run original en lugar de crear un duplicado. Los reintentos automaticos son seguros.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
DataEngineHttpError: () => DataEngineHttpError,
|
|
24
|
+
DataEngineReporter: () => DataEngineReporter,
|
|
25
|
+
createClient: () => createClient,
|
|
26
|
+
detectPipeline: () => detectPipeline,
|
|
27
|
+
loadConfig: () => loadConfig,
|
|
28
|
+
mergePipeline: () => mergePipeline
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(index_exports);
|
|
31
|
+
|
|
32
|
+
// src/client.ts
|
|
33
|
+
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
34
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
35
|
+
var RETRY_DELAYS_MS = [200, 600, 1800];
|
|
36
|
+
var DataEngineHttpError = class extends Error {
|
|
37
|
+
status;
|
|
38
|
+
errors;
|
|
39
|
+
constructor(status, message, errors) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = "DataEngineHttpError";
|
|
42
|
+
this.status = status;
|
|
43
|
+
this.errors = errors;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
function sleep(ms) {
|
|
47
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
48
|
+
}
|
|
49
|
+
function isRetriable(status) {
|
|
50
|
+
return status >= 500 && status < 600;
|
|
51
|
+
}
|
|
52
|
+
function createClient(options) {
|
|
53
|
+
const {
|
|
54
|
+
apiKey,
|
|
55
|
+
baseUrl,
|
|
56
|
+
fetch: fetchImpl = fetch,
|
|
57
|
+
timeoutMs = DEFAULT_TIMEOUT_MS,
|
|
58
|
+
maxRetries = DEFAULT_MAX_RETRIES
|
|
59
|
+
} = options;
|
|
60
|
+
const trimmedBase = baseUrl.replace(/\/+$/, "");
|
|
61
|
+
async function post(payload) {
|
|
62
|
+
const controller = new AbortController();
|
|
63
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
64
|
+
try {
|
|
65
|
+
return await fetchImpl(`${trimmedBase}/api/v1/test-runs`, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: {
|
|
68
|
+
"content-type": "application/json",
|
|
69
|
+
authorization: `Bearer ${apiKey}`
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify(payload),
|
|
72
|
+
signal: controller.signal
|
|
73
|
+
});
|
|
74
|
+
} finally {
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function submitRun(payload) {
|
|
79
|
+
let lastError;
|
|
80
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
81
|
+
try {
|
|
82
|
+
const res = await post(payload);
|
|
83
|
+
if (res.ok) {
|
|
84
|
+
return await res.json();
|
|
85
|
+
}
|
|
86
|
+
const bodyText = await res.text().catch(() => "");
|
|
87
|
+
const parsed = bodyText ? safeJson(bodyText) : null;
|
|
88
|
+
const message = (parsed && typeof parsed === "object" && "message" in parsed ? String(parsed.message) : void 0) ?? `HTTP ${res.status}`;
|
|
89
|
+
const errors = parsed && typeof parsed === "object" && "errors" in parsed ? parsed.errors : void 0;
|
|
90
|
+
const err = new DataEngineHttpError(res.status, message, errors);
|
|
91
|
+
if (!isRetriable(res.status) || attempt === maxRetries) throw err;
|
|
92
|
+
lastError = err;
|
|
93
|
+
} catch (e) {
|
|
94
|
+
if (e instanceof DataEngineHttpError && !isRetriable(e.status)) throw e;
|
|
95
|
+
lastError = e;
|
|
96
|
+
if (attempt === maxRetries) throw e;
|
|
97
|
+
}
|
|
98
|
+
await sleep(RETRY_DELAYS_MS[attempt] ?? RETRY_DELAYS_MS[RETRY_DELAYS_MS.length - 1]);
|
|
99
|
+
}
|
|
100
|
+
throw lastError instanceof Error ? lastError : new Error("submitRun failed");
|
|
101
|
+
}
|
|
102
|
+
return { submitRun };
|
|
103
|
+
}
|
|
104
|
+
function safeJson(text) {
|
|
105
|
+
try {
|
|
106
|
+
return JSON.parse(text);
|
|
107
|
+
} catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// src/config.ts
|
|
113
|
+
function pickString(...values) {
|
|
114
|
+
for (const v of values) {
|
|
115
|
+
if (typeof v === "string" && v.length > 0) return v;
|
|
116
|
+
}
|
|
117
|
+
return void 0;
|
|
118
|
+
}
|
|
119
|
+
function parseBool(v) {
|
|
120
|
+
return v === "true" || v === "1" || v === "yes";
|
|
121
|
+
}
|
|
122
|
+
function loadConfig(overrides = {}, env = process.env) {
|
|
123
|
+
const apiKey = pickString(overrides.apiKey, env.DATA_ENGINE_API_KEY);
|
|
124
|
+
const baseUrl = pickString(overrides.baseUrl, env.DATA_ENGINE_BASE_URL);
|
|
125
|
+
const environment = pickString(overrides.environment, env.DATA_ENGINE_ENVIRONMENT);
|
|
126
|
+
const missing = [];
|
|
127
|
+
if (!apiKey) missing.push("DATA_ENGINE_API_KEY");
|
|
128
|
+
if (!baseUrl) missing.push("DATA_ENGINE_BASE_URL");
|
|
129
|
+
if (!environment) missing.push("DATA_ENGINE_ENVIRONMENT");
|
|
130
|
+
const disabled = overrides.disabled ?? parseBool(env.DATA_ENGINE_DISABLE);
|
|
131
|
+
const strict = overrides.strict ?? parseBool(env.DATA_ENGINE_STRICT);
|
|
132
|
+
if (missing.length > 0) return { ok: false, missing };
|
|
133
|
+
return {
|
|
134
|
+
ok: true,
|
|
135
|
+
missing: [],
|
|
136
|
+
config: {
|
|
137
|
+
apiKey,
|
|
138
|
+
baseUrl: baseUrl.replace(/\/+$/, ""),
|
|
139
|
+
environment,
|
|
140
|
+
branch: pickString(overrides.branch, env.DATA_ENGINE_BRANCH),
|
|
141
|
+
commitSha: pickString(overrides.commitSha, env.DATA_ENGINE_COMMIT_SHA),
|
|
142
|
+
triggeredBy: pickString(overrides.triggeredBy, env.DATA_ENGINE_TRIGGERED_BY),
|
|
143
|
+
pipelineRunUrl: pickString(
|
|
144
|
+
overrides.pipelineRunUrl,
|
|
145
|
+
env.DATA_ENGINE_PIPELINE_RUN_URL
|
|
146
|
+
),
|
|
147
|
+
strict,
|
|
148
|
+
disabled
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/pipeline/providers/github.ts
|
|
154
|
+
function detectGitHub(env) {
|
|
155
|
+
if (env.GITHUB_ACTIONS !== "true") return null;
|
|
156
|
+
const server = env.GITHUB_SERVER_URL;
|
|
157
|
+
const repo = env.GITHUB_REPOSITORY;
|
|
158
|
+
const runId = env.GITHUB_RUN_ID;
|
|
159
|
+
const pipelineRunUrl = server && repo && runId ? `${server}/${repo}/actions/runs/${runId}` : void 0;
|
|
160
|
+
return {
|
|
161
|
+
provider: "github",
|
|
162
|
+
branch: env.GITHUB_REF_NAME,
|
|
163
|
+
commitSha: env.GITHUB_SHA,
|
|
164
|
+
triggeredBy: env.GITHUB_ACTOR,
|
|
165
|
+
pipelineRunUrl
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/pipeline/providers/azure.ts
|
|
170
|
+
function detectAzure(env) {
|
|
171
|
+
if (env.TF_BUILD !== "True" && env.TF_BUILD !== "true") return null;
|
|
172
|
+
const collection = env.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI;
|
|
173
|
+
const project = env.SYSTEM_TEAMPROJECT;
|
|
174
|
+
const buildId = env.BUILD_BUILDID;
|
|
175
|
+
const pipelineRunUrl = collection && project && buildId ? `${collection.replace(/\/+$/, "")}/${encodeURIComponent(project)}/_build/results?buildId=${buildId}` : void 0;
|
|
176
|
+
return {
|
|
177
|
+
provider: "azure",
|
|
178
|
+
branch: env.BUILD_SOURCEBRANCHNAME,
|
|
179
|
+
commitSha: env.BUILD_SOURCEVERSION,
|
|
180
|
+
triggeredBy: env.BUILD_REQUESTEDFOR,
|
|
181
|
+
pipelineRunUrl
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// src/pipeline/providers/gitlab.ts
|
|
186
|
+
function detectGitLab(env) {
|
|
187
|
+
if (env.GITLAB_CI !== "true") return null;
|
|
188
|
+
return {
|
|
189
|
+
provider: "gitlab",
|
|
190
|
+
branch: env.CI_COMMIT_REF_NAME,
|
|
191
|
+
commitSha: env.CI_COMMIT_SHA,
|
|
192
|
+
triggeredBy: env.GITLAB_USER_LOGIN,
|
|
193
|
+
pipelineRunUrl: env.CI_PIPELINE_URL
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// src/pipeline/providers/generic.ts
|
|
198
|
+
function detectGeneric(env) {
|
|
199
|
+
if (env.CI !== "true" && env.CI !== "1") return null;
|
|
200
|
+
return {
|
|
201
|
+
provider: "generic",
|
|
202
|
+
branch: env.CI_COMMIT_REF_NAME ?? env.GIT_BRANCH,
|
|
203
|
+
commitSha: env.CI_COMMIT_SHA ?? env.GIT_COMMIT,
|
|
204
|
+
triggeredBy: env.USER,
|
|
205
|
+
pipelineRunUrl: void 0
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// src/pipeline/detect.ts
|
|
210
|
+
function detectPipeline(env = process.env) {
|
|
211
|
+
return detectGitHub(env) ?? detectAzure(env) ?? detectGitLab(env) ?? detectGeneric(env) ?? { provider: "unknown" };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// src/pipeline/merge.ts
|
|
215
|
+
function mergePipeline(detected, config) {
|
|
216
|
+
return {
|
|
217
|
+
branch: config.branch ?? detected.branch,
|
|
218
|
+
commitSha: config.commitSha ?? detected.commitSha,
|
|
219
|
+
triggeredBy: config.triggeredBy ?? detected.triggeredBy,
|
|
220
|
+
pipelineRunUrl: config.pipelineRunUrl ?? detected.pipelineRunUrl,
|
|
221
|
+
provider: detected.provider
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// src/playwright/reporter.ts
|
|
226
|
+
var import_node_crypto = require("crypto");
|
|
227
|
+
|
|
228
|
+
// src/playwright/map-result.ts
|
|
229
|
+
var ERROR_MESSAGE_MAX = 4e3;
|
|
230
|
+
function truncate(s, max) {
|
|
231
|
+
return s.length > max ? s.slice(0, max) : s;
|
|
232
|
+
}
|
|
233
|
+
function mapStatus(pw, retry) {
|
|
234
|
+
if (pw === "skipped") return "SKIPPED";
|
|
235
|
+
if (pw === "passed") return retry > 0 ? "FLAKY" : "PASSED";
|
|
236
|
+
return "FAILED";
|
|
237
|
+
}
|
|
238
|
+
function suiteOf(test) {
|
|
239
|
+
const parts = test.titlePath ? test.titlePath() : test.parent?.titlePath?.() ?? [];
|
|
240
|
+
const withoutLeaf = parts.slice(0, Math.max(0, parts.length - 1)).filter(Boolean);
|
|
241
|
+
if (withoutLeaf.length > 0) return withoutLeaf.join(" > ");
|
|
242
|
+
return test.location?.file ?? "unknown";
|
|
243
|
+
}
|
|
244
|
+
function mapPlaywrightResult(test, result) {
|
|
245
|
+
const status = mapStatus(result.status, result.retry);
|
|
246
|
+
const rawError = result.errors?.[0]?.message;
|
|
247
|
+
return {
|
|
248
|
+
name: test.title,
|
|
249
|
+
suite: suiteOf(test),
|
|
250
|
+
status,
|
|
251
|
+
durationMs: Math.max(0, Math.round(result.duration)),
|
|
252
|
+
errorMessage: rawError ? truncate(rawError, ERROR_MESSAGE_MAX) : void 0,
|
|
253
|
+
retries: result.retry,
|
|
254
|
+
tags: []
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/playwright/reporter.ts
|
|
259
|
+
var DataEngineReporter = class {
|
|
260
|
+
enabled = false;
|
|
261
|
+
config;
|
|
262
|
+
client;
|
|
263
|
+
pipeline;
|
|
264
|
+
framework;
|
|
265
|
+
startedAt = /* @__PURE__ */ new Date();
|
|
266
|
+
buffered = /* @__PURE__ */ new Map();
|
|
267
|
+
injectedClient;
|
|
268
|
+
constructor(options = {}) {
|
|
269
|
+
this.framework = options.framework ?? "PLAYWRIGHT";
|
|
270
|
+
this.injectedClient = options.client;
|
|
271
|
+
this.pendingOverrides = {
|
|
272
|
+
apiKey: options.apiKey,
|
|
273
|
+
baseUrl: options.baseUrl,
|
|
274
|
+
environment: options.environment,
|
|
275
|
+
branch: options.branch,
|
|
276
|
+
commitSha: options.commitSha,
|
|
277
|
+
triggeredBy: options.triggeredBy,
|
|
278
|
+
pipelineRunUrl: options.pipelineRunUrl,
|
|
279
|
+
strict: options.strict,
|
|
280
|
+
disabled: options.disabled
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
pendingOverrides;
|
|
284
|
+
printsToStdio() {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
onBegin() {
|
|
288
|
+
this.startedAt = /* @__PURE__ */ new Date();
|
|
289
|
+
const loaded = loadConfig(this.pendingOverrides);
|
|
290
|
+
if (!loaded.ok) {
|
|
291
|
+
this.warnOnce(
|
|
292
|
+
`[data-engine] reporter disabled \u2014 missing: ${loaded.missing.join(", ")}`
|
|
293
|
+
);
|
|
294
|
+
this.enabled = false;
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
this.config = loaded.config;
|
|
298
|
+
if (this.config.disabled) {
|
|
299
|
+
this.warnOnce("[data-engine] reporter disabled via DATA_ENGINE_DISABLE");
|
|
300
|
+
this.enabled = false;
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
this.client = this.injectedClient ?? createClient({ apiKey: this.config.apiKey, baseUrl: this.config.baseUrl });
|
|
304
|
+
this.pipeline = mergePipeline(detectPipeline(), this.config);
|
|
305
|
+
this.enabled = true;
|
|
306
|
+
}
|
|
307
|
+
onTestEnd(test, result) {
|
|
308
|
+
if (!this.enabled) return;
|
|
309
|
+
this.buffered.set(test.id, mapPlaywrightResult(test, result));
|
|
310
|
+
}
|
|
311
|
+
async onEnd() {
|
|
312
|
+
if (!this.enabled || !this.client || !this.config || !this.pipeline) return;
|
|
313
|
+
const results = Array.from(this.buffered.values());
|
|
314
|
+
if (results.length === 0) return;
|
|
315
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
316
|
+
const payload = {
|
|
317
|
+
runId: (0, import_node_crypto.randomUUID)(),
|
|
318
|
+
framework: this.framework,
|
|
319
|
+
environment: this.config.environment,
|
|
320
|
+
branch: this.pipeline.branch ?? "unknown",
|
|
321
|
+
commitSha: this.pipeline.commitSha,
|
|
322
|
+
triggeredBy: this.pipeline.triggeredBy,
|
|
323
|
+
pipelineRunUrl: this.pipeline.pipelineRunUrl,
|
|
324
|
+
startedAt: this.startedAt.toISOString(),
|
|
325
|
+
finishedAt: finishedAt.toISOString(),
|
|
326
|
+
results
|
|
327
|
+
};
|
|
328
|
+
try {
|
|
329
|
+
await this.client.submitRun(payload);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
332
|
+
if (this.config.strict) {
|
|
333
|
+
throw error;
|
|
334
|
+
}
|
|
335
|
+
console.warn(`[data-engine] submit failed: ${msg}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
warned = false;
|
|
339
|
+
warnOnce(message) {
|
|
340
|
+
if (this.warned) return;
|
|
341
|
+
this.warned = true;
|
|
342
|
+
console.warn(message);
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
346
|
+
0 && (module.exports = {
|
|
347
|
+
DataEngineHttpError,
|
|
348
|
+
DataEngineReporter,
|
|
349
|
+
createClient,
|
|
350
|
+
detectPipeline,
|
|
351
|
+
loadConfig,
|
|
352
|
+
mergePipeline
|
|
353
|
+
});
|
|
354
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/config.ts","../src/pipeline/providers/github.ts","../src/pipeline/providers/azure.ts","../src/pipeline/providers/gitlab.ts","../src/pipeline/providers/generic.ts","../src/pipeline/detect.ts","../src/pipeline/merge.ts","../src/playwright/reporter.ts","../src/playwright/map-result.ts"],"sourcesContent":["export { createClient, DataEngineHttpError } from \"./client.js\";\nexport { loadConfig } from \"./config.js\";\nexport { detectPipeline } from \"./pipeline/detect.js\";\nexport { mergePipeline } from \"./pipeline/merge.js\";\nexport { default as DataEngineReporter } from \"./playwright/reporter.js\";\nexport type {\n Client,\n ClientOptions,\n} from \"./client.js\";\nexport type {\n Framework,\n PipelineContext,\n ReporterOverrides,\n SdkConfig,\n SubmitRunError,\n SubmitRunErrorItem,\n SubmitRunResponse,\n TestResultPayload,\n TestResultStatus,\n TestRunPayload,\n} from \"./types.js\";\n","import type {\n SubmitRunError,\n SubmitRunResponse,\n TestRunPayload,\n} from \"./types.js\";\n\nexport type ClientOptions = {\n apiKey: string;\n baseUrl: string;\n fetch?: typeof fetch;\n timeoutMs?: number;\n maxRetries?: number;\n};\n\nexport type Client = {\n submitRun(payload: TestRunPayload): Promise<SubmitRunResponse>;\n};\n\nconst DEFAULT_TIMEOUT_MS = 15_000;\nconst DEFAULT_MAX_RETRIES = 3;\nconst RETRY_DELAYS_MS = [200, 600, 1800];\n\nexport class DataEngineHttpError extends Error implements SubmitRunError {\n readonly status: number;\n readonly errors?: SubmitRunError[\"errors\"];\n constructor(status: number, message: string, errors?: SubmitRunError[\"errors\"]) {\n super(message);\n this.name = \"DataEngineHttpError\";\n this.status = status;\n this.errors = errors;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nfunction isRetriable(status: number): boolean {\n return status >= 500 && status < 600;\n}\n\nexport function createClient(options: ClientOptions): Client {\n const {\n apiKey,\n baseUrl,\n fetch: fetchImpl = fetch,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = options;\n const trimmedBase = baseUrl.replace(/\\/+$/, \"\");\n\n async function post(payload: TestRunPayload): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n return await fetchImpl(`${trimmedBase}/api/v1/test-runs`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify(payload),\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n }\n\n async function submitRun(payload: TestRunPayload): Promise<SubmitRunResponse> {\n let lastError: unknown;\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const res = await post(payload);\n if (res.ok) {\n return (await res.json()) as SubmitRunResponse;\n }\n const bodyText = await res.text().catch(() => \"\");\n const parsed = bodyText ? safeJson(bodyText) : null;\n const message =\n (parsed && typeof parsed === \"object\" && \"message\" in parsed\n ? String((parsed as { message: unknown }).message)\n : undefined) ?? `HTTP ${res.status}`;\n const errors =\n parsed && typeof parsed === \"object\" && \"errors\" in parsed\n ? ((parsed as { errors: SubmitRunError[\"errors\"] }).errors)\n : undefined;\n const err = new DataEngineHttpError(res.status, message, errors);\n if (!isRetriable(res.status) || attempt === maxRetries) throw err;\n lastError = err;\n } catch (e) {\n if (e instanceof DataEngineHttpError && !isRetriable(e.status)) throw e;\n lastError = e;\n if (attempt === maxRetries) throw e;\n }\n await sleep(RETRY_DELAYS_MS[attempt] ?? RETRY_DELAYS_MS[RETRY_DELAYS_MS.length - 1]);\n }\n throw lastError instanceof Error ? lastError : new Error(\"submitRun failed\");\n }\n\n return { submitRun };\n}\n\nfunction safeJson(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return null;\n }\n}\n","import type { ReporterOverrides, SdkConfig } from \"./types.js\";\n\nexport type LoadConfigResult =\n | { ok: true; config: SdkConfig; missing: [] }\n | { ok: false; missing: string[] };\n\nfunction pickString(...values: Array<string | undefined>): string | undefined {\n for (const v of values) {\n if (typeof v === \"string\" && v.length > 0) return v;\n }\n return undefined;\n}\n\nfunction parseBool(v: string | undefined): boolean {\n return v === \"true\" || v === \"1\" || v === \"yes\";\n}\n\n// Precedence per field: overrides > env var > (detector merged elsewhere)\nexport function loadConfig(\n overrides: ReporterOverrides = {},\n env: NodeJS.ProcessEnv = process.env,\n): LoadConfigResult {\n const apiKey = pickString(overrides.apiKey, env.DATA_ENGINE_API_KEY);\n const baseUrl = pickString(overrides.baseUrl, env.DATA_ENGINE_BASE_URL);\n const environment = pickString(overrides.environment, env.DATA_ENGINE_ENVIRONMENT);\n\n const missing: string[] = [];\n if (!apiKey) missing.push(\"DATA_ENGINE_API_KEY\");\n if (!baseUrl) missing.push(\"DATA_ENGINE_BASE_URL\");\n if (!environment) missing.push(\"DATA_ENGINE_ENVIRONMENT\");\n\n const disabled = overrides.disabled ?? parseBool(env.DATA_ENGINE_DISABLE);\n const strict = overrides.strict ?? parseBool(env.DATA_ENGINE_STRICT);\n\n if (missing.length > 0) return { ok: false, missing };\n\n return {\n ok: true,\n missing: [],\n config: {\n apiKey: apiKey!,\n baseUrl: baseUrl!.replace(/\\/+$/, \"\"),\n environment: environment!,\n branch: pickString(overrides.branch, env.DATA_ENGINE_BRANCH),\n commitSha: pickString(overrides.commitSha, env.DATA_ENGINE_COMMIT_SHA),\n triggeredBy: pickString(overrides.triggeredBy, env.DATA_ENGINE_TRIGGERED_BY),\n pipelineRunUrl: pickString(\n overrides.pipelineRunUrl,\n env.DATA_ENGINE_PIPELINE_RUN_URL,\n ),\n strict,\n disabled,\n },\n };\n}\n","import type { PipelineContext } from \"../../types.js\";\n\n// GitHub Actions env reference:\n// GITHUB_ACTIONS=true, GITHUB_REF_NAME=branch, GITHUB_SHA=commit,\n// GITHUB_SERVER_URL + GITHUB_REPOSITORY + GITHUB_RUN_ID → run URL,\n// GITHUB_ACTOR=triggered by\nexport function detectGitHub(env: NodeJS.ProcessEnv): PipelineContext | null {\n if (env.GITHUB_ACTIONS !== \"true\") return null;\n const server = env.GITHUB_SERVER_URL;\n const repo = env.GITHUB_REPOSITORY;\n const runId = env.GITHUB_RUN_ID;\n const pipelineRunUrl =\n server && repo && runId ? `${server}/${repo}/actions/runs/${runId}` : undefined;\n return {\n provider: \"github\",\n branch: env.GITHUB_REF_NAME,\n commitSha: env.GITHUB_SHA,\n triggeredBy: env.GITHUB_ACTOR,\n pipelineRunUrl,\n };\n}\n","import type { PipelineContext } from \"../../types.js\";\n\n// Azure Pipelines env reference:\n// TF_BUILD=True, BUILD_SOURCEBRANCHNAME=branch, BUILD_SOURCEVERSION=commit,\n// SYSTEM_TEAMFOUNDATIONCOLLECTIONURI + SYSTEM_TEAMPROJECT + BUILD_BUILDID → run URL,\n// BUILD_REQUESTEDFOR=triggered by (display name)\nexport function detectAzure(env: NodeJS.ProcessEnv): PipelineContext | null {\n if (env.TF_BUILD !== \"True\" && env.TF_BUILD !== \"true\") return null;\n const collection = env.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI;\n const project = env.SYSTEM_TEAMPROJECT;\n const buildId = env.BUILD_BUILDID;\n const pipelineRunUrl =\n collection && project && buildId\n ? `${collection.replace(/\\/+$/, \"\")}/${encodeURIComponent(project)}/_build/results?buildId=${buildId}`\n : undefined;\n return {\n provider: \"azure\",\n branch: env.BUILD_SOURCEBRANCHNAME,\n commitSha: env.BUILD_SOURCEVERSION,\n triggeredBy: env.BUILD_REQUESTEDFOR,\n pipelineRunUrl,\n };\n}\n","import type { PipelineContext } from \"../../types.js\";\n\n// GitLab CI env reference:\n// GITLAB_CI=true, CI_COMMIT_REF_NAME=branch, CI_COMMIT_SHA=commit,\n// CI_PIPELINE_URL=run URL, GITLAB_USER_LOGIN=triggered by\nexport function detectGitLab(env: NodeJS.ProcessEnv): PipelineContext | null {\n if (env.GITLAB_CI !== \"true\") return null;\n return {\n provider: \"gitlab\",\n branch: env.CI_COMMIT_REF_NAME,\n commitSha: env.CI_COMMIT_SHA,\n triggeredBy: env.GITLAB_USER_LOGIN,\n pipelineRunUrl: env.CI_PIPELINE_URL,\n };\n}\n","import type { PipelineContext } from \"../../types.js\";\n\n// Generic CI fallback: only fires when CI=true and no known provider matched.\n// Reads a handful of widely-set env vars but does not shell out to git.\nexport function detectGeneric(env: NodeJS.ProcessEnv): PipelineContext | null {\n if (env.CI !== \"true\" && env.CI !== \"1\") return null;\n return {\n provider: \"generic\",\n branch: env.CI_COMMIT_REF_NAME ?? env.GIT_BRANCH,\n commitSha: env.CI_COMMIT_SHA ?? env.GIT_COMMIT,\n triggeredBy: env.USER,\n pipelineRunUrl: undefined,\n };\n}\n","import type { PipelineContext } from \"../types.js\";\nimport { detectGitHub } from \"./providers/github.js\";\nimport { detectAzure } from \"./providers/azure.js\";\nimport { detectGitLab } from \"./providers/gitlab.js\";\nimport { detectGeneric } from \"./providers/generic.js\";\n\nexport function detectPipeline(\n env: NodeJS.ProcessEnv = process.env,\n): PipelineContext {\n return (\n detectGitHub(env) ??\n detectAzure(env) ??\n detectGitLab(env) ??\n detectGeneric(env) ?? { provider: \"unknown\" }\n );\n}\n","import type { PipelineContext, SdkConfig } from \"../types.js\";\n\n// Merge detected pipeline context with SdkConfig overrides.\n// The config field wins whenever it is defined; detector fills the gaps.\nexport type MergedPipeline = {\n branch: string | undefined;\n commitSha: string | undefined;\n triggeredBy: string | undefined;\n pipelineRunUrl: string | undefined;\n provider: PipelineContext[\"provider\"];\n};\n\nexport function mergePipeline(\n detected: PipelineContext,\n config: SdkConfig,\n): MergedPipeline {\n return {\n branch: config.branch ?? detected.branch,\n commitSha: config.commitSha ?? detected.commitSha,\n triggeredBy: config.triggeredBy ?? detected.triggeredBy,\n pipelineRunUrl: config.pipelineRunUrl ?? detected.pipelineRunUrl,\n provider: detected.provider,\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { Reporter, TestCase, TestResult } from \"@playwright/test/reporter\";\nimport { loadConfig } from \"../config.js\";\nimport { createClient, type Client } from \"../client.js\";\nimport { detectPipeline } from \"../pipeline/detect.js\";\nimport { mergePipeline, type MergedPipeline } from \"../pipeline/merge.js\";\nimport { mapPlaywrightResult } from \"./map-result.js\";\nimport type {\n Framework,\n ReporterOverrides,\n SdkConfig,\n TestResultPayload,\n} from \"../types.js\";\n\nexport type DataEngineReporterOptions = ReporterOverrides & {\n framework?: Framework;\n /**\n * Inject a client for testing. Not intended for production use.\n * @internal\n */\n client?: Client;\n};\n\n// Custom Playwright Reporter that captures the full run + pipeline context\n// and posts it to POST /api/v1/test-runs on portal shutdown.\n//\n// Fail-open by default: any network / config error is warned but never thrown.\n// DATA_ENGINE_STRICT=true flips to fail-loud.\nexport default class DataEngineReporter implements Reporter {\n private enabled = false;\n private config?: SdkConfig;\n private client?: Client;\n private pipeline?: MergedPipeline;\n private framework: Framework;\n private startedAt = new Date();\n private buffered = new Map<string, TestResultPayload>();\n private injectedClient?: Client;\n\n constructor(options: DataEngineReporterOptions = {}) {\n this.framework = options.framework ?? \"PLAYWRIGHT\";\n this.injectedClient = options.client;\n // Stash overrides (minus the framework/client-specific keys) for onBegin.\n this.pendingOverrides = {\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n environment: options.environment,\n branch: options.branch,\n commitSha: options.commitSha,\n triggeredBy: options.triggeredBy,\n pipelineRunUrl: options.pipelineRunUrl,\n strict: options.strict,\n disabled: options.disabled,\n };\n }\n\n private pendingOverrides: ReporterOverrides;\n\n printsToStdio(): boolean {\n return false;\n }\n\n onBegin(): void {\n this.startedAt = new Date();\n const loaded = loadConfig(this.pendingOverrides);\n if (!loaded.ok) {\n this.warnOnce(\n `[data-engine] reporter disabled — missing: ${loaded.missing.join(\", \")}`,\n );\n this.enabled = false;\n return;\n }\n this.config = loaded.config;\n if (this.config.disabled) {\n this.warnOnce(\"[data-engine] reporter disabled via DATA_ENGINE_DISABLE\");\n this.enabled = false;\n return;\n }\n this.client =\n this.injectedClient ??\n createClient({ apiKey: this.config.apiKey, baseUrl: this.config.baseUrl });\n this.pipeline = mergePipeline(detectPipeline(), this.config);\n this.enabled = true;\n }\n\n onTestEnd(test: TestCase, result: TestResult): void {\n if (!this.enabled) return;\n // Playwright fires onTestEnd once per attempt. We keep the latest by test.id\n // so retries collapse into a single result (the final attempt wins).\n this.buffered.set(test.id, mapPlaywrightResult(test, result));\n }\n\n async onEnd(): Promise<void> {\n if (!this.enabled || !this.client || !this.config || !this.pipeline) return;\n const results = Array.from(this.buffered.values());\n if (results.length === 0) return;\n\n const finishedAt = new Date();\n const payload = {\n runId: randomUUID(),\n framework: this.framework,\n environment: this.config.environment,\n branch: this.pipeline.branch ?? \"unknown\",\n commitSha: this.pipeline.commitSha,\n triggeredBy: this.pipeline.triggeredBy,\n pipelineRunUrl: this.pipeline.pipelineRunUrl,\n startedAt: this.startedAt.toISOString(),\n finishedAt: finishedAt.toISOString(),\n results,\n };\n\n try {\n await this.client.submitRun(payload);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n if (this.config.strict) {\n throw error;\n }\n console.warn(`[data-engine] submit failed: ${msg}`);\n }\n }\n\n private warned = false;\n private warnOnce(message: string): void {\n if (this.warned) return;\n this.warned = true;\n console.warn(message);\n }\n}\n","import type { TestResultPayload, TestResultStatus } from \"../types.js\";\n\n// Minimal shape of Playwright's TestCase/TestResult that we consume.\n// We don't import from @playwright/test to keep this module test-friendly\n// and avoid a hard runtime dependency; the Reporter imports the real types.\nexport type MinimalTestCase = {\n id: string;\n title: string;\n location?: { file?: string };\n parent?: { titlePath?: () => string[] };\n titlePath?: () => string[];\n};\n\nexport type MinimalTestResult = {\n status: \"passed\" | \"failed\" | \"timedOut\" | \"skipped\" | \"interrupted\";\n duration: number;\n retry: number;\n errors: Array<{ message?: string }>;\n};\n\nconst ERROR_MESSAGE_MAX = 4000;\n\nfunction truncate(s: string, max: number): string {\n return s.length > max ? s.slice(0, max) : s;\n}\n\nfunction mapStatus(\n pw: MinimalTestResult[\"status\"],\n retry: number,\n): TestResultStatus {\n if (pw === \"skipped\") return \"SKIPPED\";\n if (pw === \"passed\") return retry > 0 ? \"FLAKY\" : \"PASSED\";\n // failed, timedOut, interrupted → FAILED\n return \"FAILED\";\n}\n\nfunction suiteOf(test: MinimalTestCase): string {\n const parts = test.titlePath ? test.titlePath() : test.parent?.titlePath?.() ?? [];\n // Playwright's titlePath returns [projectName?, file, ...describes, testTitle].\n // We drop the last entry (test title) and empty leading entries.\n const withoutLeaf = parts.slice(0, Math.max(0, parts.length - 1)).filter(Boolean);\n if (withoutLeaf.length > 0) return withoutLeaf.join(\" > \");\n return test.location?.file ?? \"unknown\";\n}\n\nexport function mapPlaywrightResult(\n test: MinimalTestCase,\n result: MinimalTestResult,\n): TestResultPayload {\n const status = mapStatus(result.status, result.retry);\n const rawError = result.errors?.[0]?.message;\n return {\n name: test.title,\n suite: suiteOf(test),\n status,\n durationMs: Math.max(0, Math.round(result.duration)),\n errorMessage: rawError ? truncate(rawError, ERROR_MESSAGE_MAX) : undefined,\n retries: result.retry,\n tags: [],\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { R as ReporterOverrides, S as SdkConfig, P as PipelineContext } from './reporter-DZCr9FGW.cjs';
|
|
2
|
+
export { C as Client, a as ClientOptions, D as DataEngineHttpError, b as DataEngineReporter, F as Framework, c as SubmitRunError, d as SubmitRunErrorItem, e as SubmitRunResponse, T as TestResultPayload, f as TestResultStatus, g as TestRunPayload, h as createClient } from './reporter-DZCr9FGW.cjs';
|
|
3
|
+
import '@playwright/test/reporter';
|
|
4
|
+
|
|
5
|
+
type LoadConfigResult = {
|
|
6
|
+
ok: true;
|
|
7
|
+
config: SdkConfig;
|
|
8
|
+
missing: [];
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
missing: string[];
|
|
12
|
+
};
|
|
13
|
+
declare function loadConfig(overrides?: ReporterOverrides, env?: NodeJS.ProcessEnv): LoadConfigResult;
|
|
14
|
+
|
|
15
|
+
declare function detectPipeline(env?: NodeJS.ProcessEnv): PipelineContext;
|
|
16
|
+
|
|
17
|
+
type MergedPipeline = {
|
|
18
|
+
branch: string | undefined;
|
|
19
|
+
commitSha: string | undefined;
|
|
20
|
+
triggeredBy: string | undefined;
|
|
21
|
+
pipelineRunUrl: string | undefined;
|
|
22
|
+
provider: PipelineContext["provider"];
|
|
23
|
+
};
|
|
24
|
+
declare function mergePipeline(detected: PipelineContext, config: SdkConfig): MergedPipeline;
|
|
25
|
+
|
|
26
|
+
export { PipelineContext, ReporterOverrides, SdkConfig, detectPipeline, loadConfig, mergePipeline };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { R as ReporterOverrides, S as SdkConfig, P as PipelineContext } from './reporter-DZCr9FGW.js';
|
|
2
|
+
export { C as Client, a as ClientOptions, D as DataEngineHttpError, b as DataEngineReporter, F as Framework, c as SubmitRunError, d as SubmitRunErrorItem, e as SubmitRunResponse, T as TestResultPayload, f as TestResultStatus, g as TestRunPayload, h as createClient } from './reporter-DZCr9FGW.js';
|
|
3
|
+
import '@playwright/test/reporter';
|
|
4
|
+
|
|
5
|
+
type LoadConfigResult = {
|
|
6
|
+
ok: true;
|
|
7
|
+
config: SdkConfig;
|
|
8
|
+
missing: [];
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
missing: string[];
|
|
12
|
+
};
|
|
13
|
+
declare function loadConfig(overrides?: ReporterOverrides, env?: NodeJS.ProcessEnv): LoadConfigResult;
|
|
14
|
+
|
|
15
|
+
declare function detectPipeline(env?: NodeJS.ProcessEnv): PipelineContext;
|
|
16
|
+
|
|
17
|
+
type MergedPipeline = {
|
|
18
|
+
branch: string | undefined;
|
|
19
|
+
commitSha: string | undefined;
|
|
20
|
+
triggeredBy: string | undefined;
|
|
21
|
+
pipelineRunUrl: string | undefined;
|
|
22
|
+
provider: PipelineContext["provider"];
|
|
23
|
+
};
|
|
24
|
+
declare function mergePipeline(detected: PipelineContext, config: SdkConfig): MergedPipeline;
|
|
25
|
+
|
|
26
|
+
export { PipelineContext, ReporterOverrides, SdkConfig, detectPipeline, loadConfig, mergePipeline };
|