@pipeline-builder/pipeline-data 4.1.23 → 4.1.25
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/lib/api/alert-destinations.d.ts +17 -0
- package/lib/api/alert-destinations.js +36 -0
- package/lib/api/reporting/analytics-queries.d.ts +274 -0
- package/lib/api/reporting/analytics-queries.js +598 -0
- package/lib/api/reporting/daily-rollup.d.ts +41 -0
- package/lib/api/reporting/daily-rollup.js +173 -0
- package/lib/api/reporting/deploy-rollup.d.ts +78 -0
- package/lib/api/reporting/deploy-rollup.js +203 -0
- package/lib/api/reporting/dora-scoring.d.ts +14 -0
- package/lib/api/reporting/dora-scoring.js +25 -1
- package/lib/api/reporting/dora.js +30 -6
- package/lib/api/reporting/failure-classifier.d.ts +54 -0
- package/lib/api/reporting/failure-classifier.js +179 -0
- package/lib/api/reporting/ingest.d.ts +2 -2
- package/lib/api/reporting/ingest.js +129 -4
- package/lib/api/reporting/last-deploy.d.ts +31 -0
- package/lib/api/reporting/last-deploy.js +93 -0
- package/lib/api/reporting/needs-attention.d.ts +93 -0
- package/lib/api/reporting/needs-attention.js +152 -0
- package/lib/api/reporting/plugin-exposure.d.ts +129 -0
- package/lib/api/reporting/plugin-exposure.js +312 -0
- package/lib/api/reporting/retention-sweep.js +9 -1
- package/lib/api/reporting/sql-helpers.d.ts +35 -2
- package/lib/api/reporting/sql-helpers.js +39 -1
- package/lib/api/reporting/stakeholder/compose.d.ts +115 -0
- package/lib/api/reporting/stakeholder/compose.js +234 -0
- package/lib/api/reporting/stakeholder/index.d.ts +14 -0
- package/lib/api/reporting/stakeholder/index.js +17 -0
- package/lib/api/reporting/stakeholder/period.d.ts +102 -0
- package/lib/api/reporting/stakeholder/period.js +273 -0
- package/lib/api/reporting/stakeholder/report-html.d.ts +93 -0
- package/lib/api/reporting/stakeholder/report-html.js +208 -0
- package/lib/api/reporting/stakeholder/sections.d.ts +117 -0
- package/lib/api/reporting/stakeholder/sections.js +249 -0
- package/lib/api/reporting/stakeholder/store.d.ts +450 -0
- package/lib/api/reporting/stakeholder/store.js +981 -0
- package/lib/api/reporting/stakeholder/templates.d.ts +21 -0
- package/lib/api/reporting/stakeholder/templates.js +104 -0
- package/lib/api/reporting/types.d.ts +73 -0
- package/lib/api/reporting/types.js +1 -1
- package/lib/api/reporting-service.d.ts +94 -5
- package/lib/api/reporting-service.js +169 -10
- package/lib/api/soft-delete-sweep.d.ts +11 -2
- package/lib/api/soft-delete-sweep.js +17 -6
- package/lib/database/drizzle-schema.d.ts +2263 -385
- package/lib/database/drizzle-schema.js +18 -7
- package/lib/database/index.d.ts +1 -1
- package/lib/database/index.js +4 -2
- package/lib/database/schema/compliance.d.ts +0 -682
- package/lib/database/schema/compliance.js +6 -66
- package/lib/database/schema/ecosystem.d.ts +20 -157
- package/lib/database/schema/ecosystem.js +23 -16
- package/lib/database/schema/pipeline.d.ts +200 -0
- package/lib/database/schema/pipeline.js +100 -1
- package/lib/database/schema/plugin.d.ts +20 -1
- package/lib/database/schema/plugin.js +13 -1
- package/lib/database/schema/reporting-analytics.d.ts +1212 -0
- package/lib/database/schema/reporting-analytics.js +250 -0
- package/lib/database/schema/reporting-stakeholder.d.ts +1405 -0
- package/lib/database/schema/reporting-stakeholder.js +251 -0
- package/lib/index.d.ts +10 -1
- package/lib/index.js +15 -1
- package/lib/testing/exports.json +67 -4
- package/package.json +4 -3
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** One destination, reduced to what a delivery needs. */
|
|
2
|
+
export interface NotificationDestination {
|
|
3
|
+
id: string;
|
|
4
|
+
/** `slack` | `webhook` | `email` | `in-app`. */
|
|
5
|
+
channel: string;
|
|
6
|
+
/** The URL or address. Bearer-equivalent for a webhook — never logged. */
|
|
7
|
+
target: string;
|
|
8
|
+
label: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Every ENABLED, undeleted destination for an org.
|
|
12
|
+
*
|
|
13
|
+
* Runs in the caller's ambient tenant context, so RLS is the tenancy gate — a caller
|
|
14
|
+
* without a context for this org reads nothing, which is the correct answer rather than
|
|
15
|
+
* an error.
|
|
16
|
+
*/
|
|
17
|
+
export declare function listEnabledAlertDestinations(orgId: string): Promise<NotificationDestination[]>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Reading an org's notification destinations.
|
|
5
|
+
*
|
|
6
|
+
* These rows are ADMIN-OWNED: an org's admins decided where this organization's
|
|
7
|
+
* notifications go, and everything that needs to notify an org reads the same list
|
|
8
|
+
* rather than growing its own copy. Platform owns the writes (create, update, test,
|
|
9
|
+
* delete) in its alert-destination service; this is the read, here so that a service
|
|
10
|
+
* with no Drizzle dependency of its own can use it.
|
|
11
|
+
*
|
|
12
|
+
* Whoever reads this list must not treat it as a URL they chose. A caller that let a
|
|
13
|
+
* user name the target would have reinvented an SSRF, which is exactly why the write
|
|
14
|
+
* side validates the channel/target pairing and the transport resolves-and-pins the host.
|
|
15
|
+
*/
|
|
16
|
+
import { and, eq, isNull } from 'drizzle-orm';
|
|
17
|
+
import { schema } from '../database/drizzle-schema.js';
|
|
18
|
+
import { withTenantTx } from '../database/tenancy.js';
|
|
19
|
+
/**
|
|
20
|
+
* Every ENABLED, undeleted destination for an org.
|
|
21
|
+
*
|
|
22
|
+
* Runs in the caller's ambient tenant context, so RLS is the tenancy gate — a caller
|
|
23
|
+
* without a context for this org reads nothing, which is the correct answer rather than
|
|
24
|
+
* an error.
|
|
25
|
+
*/
|
|
26
|
+
export async function listEnabledAlertDestinations(orgId) {
|
|
27
|
+
const rows = await withTenantTx((tx) => tx.select({
|
|
28
|
+
id: schema.orgAlertDestination.id,
|
|
29
|
+
channel: schema.orgAlertDestination.channel,
|
|
30
|
+
target: schema.orgAlertDestination.target,
|
|
31
|
+
label: schema.orgAlertDestination.label,
|
|
32
|
+
}).from(schema.orgAlertDestination)
|
|
33
|
+
.where(and(eq(schema.orgAlertDestination.orgId, orgId), eq(schema.orgAlertDestination.enabled, true), isNull(schema.orgAlertDestination.deletedAt))));
|
|
34
|
+
return rows;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxlcnQtZGVzdGluYXRpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9hbGVydC1kZXN0aW5hdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7Ozs7Ozs7O0dBWUc7QUFFSCxPQUFPLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDOUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQVl0RDs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLDRCQUE0QixDQUFDLEtBQWE7SUFDOUQsTUFBTSxJQUFJLEdBQUcsTUFBTSxZQUFZLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUM7UUFDaEQsRUFBRSxFQUFFLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFO1FBQ2pDLE9BQU8sRUFBRSxNQUFNLENBQUMsbUJBQW1CLENBQUMsT0FBTztRQUMzQyxNQUFNLEVBQUUsTUFBTSxDQUFDLG1CQUFtQixDQUFDLE1BQU07UUFDekMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLO0tBQ3hDLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLG1CQUFtQixDQUFDO1NBQ2hDLEtBQUssQ0FBQyxHQUFHLENBQ1IsRUFBRSxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLEVBQzNDLEVBQUUsQ0FBQyxNQUFNLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUM1QyxNQUFNLENBQUMsTUFBTSxDQUFDLG1CQUFtQixDQUFDLFNBQVMsQ0FBQyxDQUM3QyxDQUFDLENBQUMsQ0FBQztJQUNOLE9BQU8sSUFBaUMsQ0FBQztBQUMzQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogUmVhZGluZyBhbiBvcmcncyBub3RpZmljYXRpb24gZGVzdGluYXRpb25zLlxuICpcbiAqIFRoZXNlIHJvd3MgYXJlIEFETUlOLU9XTkVEOiBhbiBvcmcncyBhZG1pbnMgZGVjaWRlZCB3aGVyZSB0aGlzIG9yZ2FuaXphdGlvbidzXG4gKiBub3RpZmljYXRpb25zIGdvLCBhbmQgZXZlcnl0aGluZyB0aGF0IG5lZWRzIHRvIG5vdGlmeSBhbiBvcmcgcmVhZHMgdGhlIHNhbWUgbGlzdFxuICogcmF0aGVyIHRoYW4gZ3Jvd2luZyBpdHMgb3duIGNvcHkuIFBsYXRmb3JtIG93bnMgdGhlIHdyaXRlcyAoY3JlYXRlLCB1cGRhdGUsIHRlc3QsXG4gKiBkZWxldGUpIGluIGl0cyBhbGVydC1kZXN0aW5hdGlvbiBzZXJ2aWNlOyB0aGlzIGlzIHRoZSByZWFkLCBoZXJlIHNvIHRoYXQgYSBzZXJ2aWNlXG4gKiB3aXRoIG5vIERyaXp6bGUgZGVwZW5kZW5jeSBvZiBpdHMgb3duIGNhbiB1c2UgaXQuXG4gKlxuICogV2hvZXZlciByZWFkcyB0aGlzIGxpc3QgbXVzdCBub3QgdHJlYXQgaXQgYXMgYSBVUkwgdGhleSBjaG9zZS4gQSBjYWxsZXIgdGhhdCBsZXQgYVxuICogdXNlciBuYW1lIHRoZSB0YXJnZXQgd291bGQgaGF2ZSByZWludmVudGVkIGFuIFNTUkYsIHdoaWNoIGlzIGV4YWN0bHkgd2h5IHRoZSB3cml0ZVxuICogc2lkZSB2YWxpZGF0ZXMgdGhlIGNoYW5uZWwvdGFyZ2V0IHBhaXJpbmcgYW5kIHRoZSB0cmFuc3BvcnQgcmVzb2x2ZXMtYW5kLXBpbnMgdGhlIGhvc3QuXG4gKi9cblxuaW1wb3J0IHsgYW5kLCBlcSwgaXNOdWxsIH0gZnJvbSAnZHJpenpsZS1vcm0nO1xuaW1wb3J0IHsgc2NoZW1hIH0gZnJvbSAnLi4vZGF0YWJhc2UvZHJpenpsZS1zY2hlbWEuanMnO1xuaW1wb3J0IHsgd2l0aFRlbmFudFR4IH0gZnJvbSAnLi4vZGF0YWJhc2UvdGVuYW5jeS5qcyc7XG5cbi8qKiBPbmUgZGVzdGluYXRpb24sIHJlZHVjZWQgdG8gd2hhdCBhIGRlbGl2ZXJ5IG5lZWRzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBOb3RpZmljYXRpb25EZXN0aW5hdGlvbiB7XG4gIGlkOiBzdHJpbmc7XG4gIC8qKiBgc2xhY2tgIHwgYHdlYmhvb2tgIHwgYGVtYWlsYCB8IGBpbi1hcHBgLiAqL1xuICBjaGFubmVsOiBzdHJpbmc7XG4gIC8qKiBUaGUgVVJMIG9yIGFkZHJlc3MuIEJlYXJlci1lcXVpdmFsZW50IGZvciBhIHdlYmhvb2sg4oCUIG5ldmVyIGxvZ2dlZC4gKi9cbiAgdGFyZ2V0OiBzdHJpbmc7XG4gIGxhYmVsOiBzdHJpbmc7XG59XG5cbi8qKlxuICogRXZlcnkgRU5BQkxFRCwgdW5kZWxldGVkIGRlc3RpbmF0aW9uIGZvciBhbiBvcmcuXG4gKlxuICogUnVucyBpbiB0aGUgY2FsbGVyJ3MgYW1iaWVudCB0ZW5hbnQgY29udGV4dCwgc28gUkxTIGlzIHRoZSB0ZW5hbmN5IGdhdGUg4oCUIGEgY2FsbGVyXG4gKiB3aXRob3V0IGEgY29udGV4dCBmb3IgdGhpcyBvcmcgcmVhZHMgbm90aGluZywgd2hpY2ggaXMgdGhlIGNvcnJlY3QgYW5zd2VyIHJhdGhlciB0aGFuXG4gKiBhbiBlcnJvci5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxpc3RFbmFibGVkQWxlcnREZXN0aW5hdGlvbnMob3JnSWQ6IHN0cmluZyk6IFByb21pc2U8Tm90aWZpY2F0aW9uRGVzdGluYXRpb25bXT4ge1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHguc2VsZWN0KHtcbiAgICBpZDogc2NoZW1hLm9yZ0FsZXJ0RGVzdGluYXRpb24uaWQsXG4gICAgY2hhbm5lbDogc2NoZW1hLm9yZ0FsZXJ0RGVzdGluYXRpb24uY2hhbm5lbCxcbiAgICB0YXJnZXQ6IHNjaGVtYS5vcmdBbGVydERlc3RpbmF0aW9uLnRhcmdldCxcbiAgICBsYWJlbDogc2NoZW1hLm9yZ0FsZXJ0RGVzdGluYXRpb24ubGFiZWwsXG4gIH0pLmZyb20oc2NoZW1hLm9yZ0FsZXJ0RGVzdGluYXRpb24pXG4gICAgLndoZXJlKGFuZChcbiAgICAgIGVxKHNjaGVtYS5vcmdBbGVydERlc3RpbmF0aW9uLm9yZ0lkLCBvcmdJZCksXG4gICAgICBlcShzY2hlbWEub3JnQWxlcnREZXN0aW5hdGlvbi5lbmFibGVkLCB0cnVlKSxcbiAgICAgIGlzTnVsbChzY2hlbWEub3JnQWxlcnREZXN0aW5hdGlvbi5kZWxldGVkQXQpLFxuICAgICkpKTtcbiAgcmV0dXJuIHJvd3MgYXMgTm90aWZpY2F0aW9uRGVzdGluYXRpb25bXTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import type { FailureCategory } from '../../database/schema/reporting-analytics.js';
|
|
2
|
+
/** The window and org scope every query takes. */
|
|
3
|
+
export interface AnalyticsScope {
|
|
4
|
+
orgId: string;
|
|
5
|
+
/** `[self, ...descendants]` for a rollup; undefined = this org only. */
|
|
6
|
+
orgIds?: string[];
|
|
7
|
+
from: string;
|
|
8
|
+
to: string;
|
|
9
|
+
}
|
|
10
|
+
/** One pipeline's line in the breakdown. */
|
|
11
|
+
export interface PipelineBreakdownRow {
|
|
12
|
+
pipelineId: string;
|
|
13
|
+
pipelineName: string | null;
|
|
14
|
+
project: string | null;
|
|
15
|
+
runs: number;
|
|
16
|
+
succeeded: number;
|
|
17
|
+
failed: number;
|
|
18
|
+
successPct: number | null;
|
|
19
|
+
p95Ms: number | null;
|
|
20
|
+
deploys: number;
|
|
21
|
+
/** The most recent failure's day and stage, for "what to look at first". */
|
|
22
|
+
lastFailureAt: string | null;
|
|
23
|
+
lastFailureStage: string | null;
|
|
24
|
+
buildSeconds: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Per-pipeline delivery, worst first.
|
|
28
|
+
*
|
|
29
|
+
* WORST FIRST, and capped, because the point of the section is "where should
|
|
30
|
+
* attention go". A list sorted by name, or an unbounded one, is a data dump: the
|
|
31
|
+
* lead still has to find the problem, which is the work the report was supposed to
|
|
32
|
+
* do. Ties break on volume, so a 50%-success pipeline that ran twice does not
|
|
33
|
+
* outrank one that ran two hundred times.
|
|
34
|
+
*
|
|
35
|
+
* `successPct` is NULL for a pipeline with no runs in the window — not 0. A
|
|
36
|
+
* pipeline nobody ran is not a pipeline that failed.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getPipelineBreakdown(scope: AnalyticsScope, limit?: number): Promise<PipelineBreakdownRow[]>;
|
|
39
|
+
/** One failure category's share of the period. */
|
|
40
|
+
export interface FailureCategoryRow {
|
|
41
|
+
category: FailureCategory;
|
|
42
|
+
label: string;
|
|
43
|
+
count: number;
|
|
44
|
+
sharePct: number;
|
|
45
|
+
/** Whether the team can act on it, or it happened to them. */
|
|
46
|
+
teamActionable: boolean;
|
|
47
|
+
/** Change vs the previous period, in failures. */
|
|
48
|
+
change: number | null;
|
|
49
|
+
/** The pipelines it hit hardest. */
|
|
50
|
+
topPipelines: Array<{
|
|
51
|
+
pipelineId: string;
|
|
52
|
+
pipelineName: string | null;
|
|
53
|
+
count: number;
|
|
54
|
+
}>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Failures by category, with the previous period's counts for the trend.
|
|
58
|
+
*
|
|
59
|
+
* SPLITS ACTIONABLE FROM NOT. A week whose failures were all cloud throttling is a
|
|
60
|
+
* different conversation from one whose failures were all broken tests, and
|
|
61
|
+
* presenting them in one ranked list invites exactly the wrong conclusion — a team
|
|
62
|
+
* being asked to fix an AWS capacity problem.
|
|
63
|
+
*/
|
|
64
|
+
export declare function getFailureAnalysis(scope: AnalyticsScope, previous?: {
|
|
65
|
+
from: string;
|
|
66
|
+
to: string;
|
|
67
|
+
}): Promise<{
|
|
68
|
+
categories: FailureCategoryRow[];
|
|
69
|
+
total: number;
|
|
70
|
+
actionableTotal: number;
|
|
71
|
+
}>;
|
|
72
|
+
/** One stage's timing, for the drill-down. */
|
|
73
|
+
export interface StagePerformanceRow {
|
|
74
|
+
stageName: string;
|
|
75
|
+
runs: number;
|
|
76
|
+
p50Ms: number | null;
|
|
77
|
+
p95Ms: number | null;
|
|
78
|
+
/** Change in p95 vs the previous period, as a percentage. */
|
|
79
|
+
p95ChangePct: number | null;
|
|
80
|
+
failed: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Per-stage timings for one pipeline, slowest first.
|
|
84
|
+
*
|
|
85
|
+
* The section a lead opens after the breakdown says a pipeline got slower: "which
|
|
86
|
+
* stage" is the next question, and answering it from raw events would mean a
|
|
87
|
+
* second scan of the same window.
|
|
88
|
+
*/
|
|
89
|
+
export declare function getStagePerformance(scope: AnalyticsScope, pipelineId: string, previous?: {
|
|
90
|
+
from: string;
|
|
91
|
+
to: string;
|
|
92
|
+
}): Promise<StagePerformanceRow[]>;
|
|
93
|
+
/** Build time by project and pipeline. No money anywhere. */
|
|
94
|
+
export interface ResourceRow {
|
|
95
|
+
project: string | null;
|
|
96
|
+
pipelineId: string;
|
|
97
|
+
pipelineName: string | null;
|
|
98
|
+
buildSeconds: number;
|
|
99
|
+
runs: number;
|
|
100
|
+
sharePct: number;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Where the build time went.
|
|
104
|
+
*
|
|
105
|
+
* SECONDS, NOT DOLLARS. A cost figure needs the instance types, the spot/on-demand
|
|
106
|
+
* mix and the account's own discounts, none of which this platform knows — so a
|
|
107
|
+
* dollar number here would be a guess presented as an invoice. Build time is the
|
|
108
|
+
* thing actually measured.
|
|
109
|
+
*/
|
|
110
|
+
export declare function getResourceConsumption(scope: AnalyticsScope, limit?: number): Promise<{
|
|
111
|
+
pipelines: ResourceRow[];
|
|
112
|
+
totalBuildSeconds: number;
|
|
113
|
+
}>;
|
|
114
|
+
/** One commit's journey across environments. */
|
|
115
|
+
export interface PromotionRow {
|
|
116
|
+
commitSha: string;
|
|
117
|
+
/** Environment → when it landed there, in the order it reached them. */
|
|
118
|
+
stops: Array<{
|
|
119
|
+
environment: string;
|
|
120
|
+
deployedAt: string;
|
|
121
|
+
hoursFromPrevious: number | null;
|
|
122
|
+
}>;
|
|
123
|
+
/** True when the commit reached a non-production environment and stopped. */
|
|
124
|
+
stuck: boolean;
|
|
125
|
+
furthest: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Where commits got to, and where they stopped.
|
|
129
|
+
*
|
|
130
|
+
* "Stuck" is the number worth reading. A commit that reached staging four days ago
|
|
131
|
+
* and never went further is work that is finished and not delivered — which does
|
|
132
|
+
* not appear in deployment frequency, success rate or lead time, because by every
|
|
133
|
+
* one of those measures nothing happened.
|
|
134
|
+
*/
|
|
135
|
+
export declare function getPromotionView(scope: AnalyticsScope, productionEnv?: string, limit?: number): Promise<{
|
|
136
|
+
commits: PromotionRow[];
|
|
137
|
+
stuckCount: number;
|
|
138
|
+
}>;
|
|
139
|
+
/** Outdated plugin usage, per pipeline and step. */
|
|
140
|
+
export interface OutdatedPluginRow {
|
|
141
|
+
pipelineId: string;
|
|
142
|
+
pipelineName: string | null;
|
|
143
|
+
stageName: string;
|
|
144
|
+
stepName: string;
|
|
145
|
+
plugin: string;
|
|
146
|
+
inUse: string | null;
|
|
147
|
+
latest: string | null;
|
|
148
|
+
gap: string | null;
|
|
149
|
+
withinPolicy: boolean;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Which pipelines are behind on a plugin, worst gap first.
|
|
153
|
+
*
|
|
154
|
+
* Reads the DECLARED side (`pipeline_plugin_resolution`). A pipeline's declared
|
|
155
|
+
* range and what it last actually ran can disagree — which is why the vulnerability
|
|
156
|
+
* section below reads the deployed side and says which it is showing.
|
|
157
|
+
*/
|
|
158
|
+
export declare function getOutdatedPlugins(scope: AnalyticsScope, limit?: number): Promise<{
|
|
159
|
+
rows: OutdatedPluginRow[];
|
|
160
|
+
behindPipelines: number;
|
|
161
|
+
majorBehind: number;
|
|
162
|
+
}>;
|
|
163
|
+
/** A pipeline's exposure to a vulnerable plugin version. */
|
|
164
|
+
export interface VulnerabilityRow {
|
|
165
|
+
pipelineId: string;
|
|
166
|
+
pipelineName: string | null;
|
|
167
|
+
plugin: string;
|
|
168
|
+
version: string;
|
|
169
|
+
/** `deployed` = what actually ran; `declared` = what the config asks for. */
|
|
170
|
+
source: string;
|
|
171
|
+
critical: number;
|
|
172
|
+
high: number;
|
|
173
|
+
findings: Array<Record<string, unknown>>;
|
|
174
|
+
flaggedAt: string;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Plugin vulnerabilities, per pipeline, Criticals first.
|
|
178
|
+
*
|
|
179
|
+
* SAYS WHETHER IT IS DECLARED OR DEPLOYED. A pipeline whose config was updated to a
|
|
180
|
+
* fixed version but which has not re-synthed is still running the vulnerable image,
|
|
181
|
+
* and a report that collapsed the two would tell a manager the problem is solved
|
|
182
|
+
* while the old image keeps running.
|
|
183
|
+
*/
|
|
184
|
+
export declare function getPluginVulnerabilities(scope: AnalyticsScope, limit?: number): Promise<{
|
|
185
|
+
rows: VulnerabilityRow[];
|
|
186
|
+
exposedPipelines: number;
|
|
187
|
+
criticalPipelines: number;
|
|
188
|
+
}>;
|
|
189
|
+
/** Adoption and deploy-tracking coverage within the reported scope. */
|
|
190
|
+
export interface AdoptionSummary {
|
|
191
|
+
activePipelines: number;
|
|
192
|
+
totalPipelines: number;
|
|
193
|
+
/** Pipelines that produced a deploy row — i.e. ones DORA can see. */
|
|
194
|
+
deployTrackedPipelines: number;
|
|
195
|
+
/** By `creation_source`, for "are the golden paths being used". */
|
|
196
|
+
bySource: Record<string, number>;
|
|
197
|
+
/** Teams in the rollup that had activity. 1 for a single-org report. */
|
|
198
|
+
activeTeams: number;
|
|
199
|
+
/** Only when the org configured the assumption. Never platform-supplied. */
|
|
200
|
+
estimatedMinutesSaved: number | null;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Adoption, coverage and creation source.
|
|
204
|
+
*
|
|
205
|
+
* `deployTrackedPipelines` is the honest denominator for everything DORA says: a
|
|
206
|
+
* pipeline that has not re-synthed with deploy tags produces no deploy rows, so it
|
|
207
|
+
* is invisible to deployment frequency — and reporting "4 deploys" without saying
|
|
208
|
+
* that 20 of 30 pipelines cannot be seen is the single most misleading thing this
|
|
209
|
+
* feature could do.
|
|
210
|
+
*/
|
|
211
|
+
export declare function getAdoption(scope: AnalyticsScope, timeSavedMinutes?: number | null): Promise<AdoptionSummary>;
|
|
212
|
+
/** One pipeline's failure streak and last successful day. */
|
|
213
|
+
export interface PipelineStreakRow {
|
|
214
|
+
pipelineId: string;
|
|
215
|
+
/**
|
|
216
|
+
* Failures in the trailing run of days on which NOTHING succeeded.
|
|
217
|
+
*
|
|
218
|
+
* A LOWER BOUND, and deliberately so. The rollup is per day, so within the most
|
|
219
|
+
* recent day that did have a success there is no way to tell whether the failures
|
|
220
|
+
* came before or after it — that day is excluded rather than guessed at. What
|
|
221
|
+
* survives is a run of failures with no success anywhere between them, which is
|
|
222
|
+
* exactly the claim the finding makes.
|
|
223
|
+
*/
|
|
224
|
+
consecutiveFailures: number;
|
|
225
|
+
/** The last day with at least one success, or null within the lookback. */
|
|
226
|
+
lastSuccessAt: Date | null;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Failure streaks and last-success dates, for the needs-attention rules.
|
|
230
|
+
*
|
|
231
|
+
* Reads the daily rollup, not `pipeline_events` — the same reason as everything
|
|
232
|
+
* else here: a streak that ended three weeks ago must still be readable after
|
|
233
|
+
* retention has swept the events that produced it.
|
|
234
|
+
*
|
|
235
|
+
* `lookbackDays` extends PAST the window on purpose. "Last succeeded 12 days ago"
|
|
236
|
+
* is the finding a weekly report most needs, and a query bounded by a 7-day window
|
|
237
|
+
* could never produce it.
|
|
238
|
+
*/
|
|
239
|
+
export declare function getPipelineStreaks(scope: AnalyticsScope, lookbackDays?: number): Promise<PipelineStreakRow[]>;
|
|
240
|
+
/**
|
|
241
|
+
* Pipelines that RAN in the window but produced no deploy rows.
|
|
242
|
+
*
|
|
243
|
+
* A measurement gap, not a failure, and the reason a deployment-frequency number can
|
|
244
|
+
* be quietly wrong: a pipeline whose synth predates the `pb.deploys` tags deploys
|
|
245
|
+
* perfectly well and is invisible to every DORA aggregate. Nothing else in the
|
|
246
|
+
* report would say so.
|
|
247
|
+
*/
|
|
248
|
+
export declare function getUntrackedPipelines(scope: AnalyticsScope): Promise<string[]>;
|
|
249
|
+
/**
|
|
250
|
+
* Pipelines running a plugin version with an OPEN Critical exposure.
|
|
251
|
+
*
|
|
252
|
+
* Point-in-time, not windowed: what matters is whether the pipeline is running one
|
|
253
|
+
* NOW. A Critical that was open last Tuesday and is fixed today is not something to
|
|
254
|
+
* put in front of a manager, and `fixed_at` is what says so.
|
|
255
|
+
*
|
|
256
|
+
* An ACCEPTED exposure is excluded. Someone with the authority to accept a risk has
|
|
257
|
+
* already decided about it in writing, with a reason and a deadline; re-raising it
|
|
258
|
+
* weekly is how a report teaches its reader to skip a section. The lapse of that
|
|
259
|
+
* acceptance is a separate finding (`lapsedAcceptances`).
|
|
260
|
+
*/
|
|
261
|
+
export declare function getVulnerablePipelines(scope: AnalyticsScope): Promise<string[]>;
|
|
262
|
+
/**
|
|
263
|
+
* When each pipeline in the window was last changed.
|
|
264
|
+
*
|
|
265
|
+
* `pipelines.updated_at`, not an audit query: the audit trail lives in another store
|
|
266
|
+
* with its own retention, and the one fact this needs — "was this touched shortly
|
|
267
|
+
* before it broke" — is already on the row, durably, in the same transaction the
|
|
268
|
+
* change was made in.
|
|
269
|
+
*
|
|
270
|
+
* The consequence is stated rather than hidden: `updated_at` moves for ANY write,
|
|
271
|
+
* including a rename. So the finding says "after a configuration change", which is
|
|
272
|
+
* true of a rename too, and does not claim to name the change.
|
|
273
|
+
*/
|
|
274
|
+
export declare function getPipelineConfigChanges(scope: AnalyticsScope): Promise<Map<string, Date>>;
|