@continuous-excellence/ze-great-dashboard-aws 0.18.4 → 0.20.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/client/.vite/manifest.json +2 -2
- package/client/assets/{index-BCZ7NCP8.css → index-Cuk6kga3.css} +1 -1
- package/client/assets/index-k3N7vI0h.js +3 -0
- package/client/assets/index-k3N7vI0h.js.map +1 -0
- package/client/index.html +2 -2
- package/dist/cli.js +96 -14
- package/dist/index.d.ts +3 -1
- package/dist/index.js +90 -10
- package/dist/lambda.mjs +631 -255
- package/dist/release.d.ts +3 -1
- package/package.json +1 -1
- package/template-ecs.yml +4 -5
- package/template.yml +4 -5
- package/client/assets/index-mtLNXa0q.js +0 -3
- package/client/assets/index-mtLNXa0q.js.map +0 -1
package/dist/lambda.mjs
CHANGED
|
@@ -3124,7 +3124,7 @@ var require_timestamp = __commonJS({
|
|
|
3124
3124
|
resolve: (str) => parseSexagesimal(str, false),
|
|
3125
3125
|
stringify: stringifySexagesimal
|
|
3126
3126
|
};
|
|
3127
|
-
var
|
|
3127
|
+
var timestamp3 = {
|
|
3128
3128
|
identify: (value) => value instanceof Date,
|
|
3129
3129
|
default: true,
|
|
3130
3130
|
tag: "tag:yaml.org,2002:timestamp",
|
|
@@ -3133,7 +3133,7 @@ var require_timestamp = __commonJS({
|
|
|
3133
3133
|
// assumed to be 00:00:00Z (start of day, UTC).
|
|
3134
3134
|
test: RegExp("^([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})(?:(?:t|T|[ \\t]+)([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}(\\.[0-9]+)?)(?:[ \\t]*(Z|[-+][012]?[0-9](?::[0-9]{2})?))?)?$"),
|
|
3135
3135
|
resolve(str) {
|
|
3136
|
-
const match2 = str.match(
|
|
3136
|
+
const match2 = str.match(timestamp3.test);
|
|
3137
3137
|
if (!match2)
|
|
3138
3138
|
throw new Error("!!timestamp expects a date, starting with yyyy-mm-dd");
|
|
3139
3139
|
const [, year2, month, day, hour, minute, second] = match2.map(Number);
|
|
@@ -3152,7 +3152,7 @@ var require_timestamp = __commonJS({
|
|
|
3152
3152
|
};
|
|
3153
3153
|
exports.floatTime = floatTime;
|
|
3154
3154
|
exports.intTime = intTime;
|
|
3155
|
-
exports.timestamp =
|
|
3155
|
+
exports.timestamp = timestamp3;
|
|
3156
3156
|
}
|
|
3157
3157
|
});
|
|
3158
3158
|
|
|
@@ -3172,7 +3172,7 @@ var require_schema3 = __commonJS({
|
|
|
3172
3172
|
var omap = require_omap();
|
|
3173
3173
|
var pairs = require_pairs();
|
|
3174
3174
|
var set2 = require_set();
|
|
3175
|
-
var
|
|
3175
|
+
var timestamp3 = require_timestamp();
|
|
3176
3176
|
var schema = [
|
|
3177
3177
|
map4.map,
|
|
3178
3178
|
seq.seq,
|
|
@@ -3192,9 +3192,9 @@ var require_schema3 = __commonJS({
|
|
|
3192
3192
|
omap.omap,
|
|
3193
3193
|
pairs.pairs,
|
|
3194
3194
|
set2.set,
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3195
|
+
timestamp3.intTime,
|
|
3196
|
+
timestamp3.floatTime,
|
|
3197
|
+
timestamp3.timestamp
|
|
3198
3198
|
];
|
|
3199
3199
|
exports.schema = schema;
|
|
3200
3200
|
}
|
|
@@ -3219,7 +3219,7 @@ var require_tags = __commonJS({
|
|
|
3219
3219
|
var pairs = require_pairs();
|
|
3220
3220
|
var schema$2 = require_schema3();
|
|
3221
3221
|
var set2 = require_set();
|
|
3222
|
-
var
|
|
3222
|
+
var timestamp3 = require_timestamp();
|
|
3223
3223
|
var schemas = /* @__PURE__ */ new Map([
|
|
3224
3224
|
["core", schema.schema],
|
|
3225
3225
|
["failsafe", [map4.map, seq.seq, string4.string]],
|
|
@@ -3233,11 +3233,11 @@ var require_tags = __commonJS({
|
|
|
3233
3233
|
float: float.float,
|
|
3234
3234
|
floatExp: float.floatExp,
|
|
3235
3235
|
floatNaN: float.floatNaN,
|
|
3236
|
-
floatTime:
|
|
3236
|
+
floatTime: timestamp3.floatTime,
|
|
3237
3237
|
int: int2.int,
|
|
3238
3238
|
intHex: int2.intHex,
|
|
3239
3239
|
intOct: int2.intOct,
|
|
3240
|
-
intTime:
|
|
3240
|
+
intTime: timestamp3.intTime,
|
|
3241
3241
|
map: map4.map,
|
|
3242
3242
|
merge: merge3.merge,
|
|
3243
3243
|
null: _null4.nullTag,
|
|
@@ -3245,7 +3245,7 @@ var require_tags = __commonJS({
|
|
|
3245
3245
|
pairs: pairs.pairs,
|
|
3246
3246
|
seq: seq.seq,
|
|
3247
3247
|
set: set2.set,
|
|
3248
|
-
timestamp:
|
|
3248
|
+
timestamp: timestamp3.timestamp
|
|
3249
3249
|
};
|
|
3250
3250
|
var coreKnownTags = {
|
|
3251
3251
|
"tag:yaml.org,2002:binary": binary.binary,
|
|
@@ -3253,7 +3253,7 @@ var require_tags = __commonJS({
|
|
|
3253
3253
|
"tag:yaml.org,2002:omap": omap.omap,
|
|
3254
3254
|
"tag:yaml.org,2002:pairs": pairs.pairs,
|
|
3255
3255
|
"tag:yaml.org,2002:set": set2.set,
|
|
3256
|
-
"tag:yaml.org,2002:timestamp":
|
|
3256
|
+
"tag:yaml.org,2002:timestamp": timestamp3.timestamp
|
|
3257
3257
|
};
|
|
3258
3258
|
function getTags(customTags, schemaName, addMergeTag) {
|
|
3259
3259
|
const schemaTags = schemas.get(schemaName);
|
|
@@ -10643,12 +10643,12 @@ var init_schema_date_utils = __esm({
|
|
|
10643
10643
|
[, month, day, hour, minute, second, fraction, year2] = matches;
|
|
10644
10644
|
}
|
|
10645
10645
|
if (year2 && second) {
|
|
10646
|
-
const
|
|
10646
|
+
const timestamp3 = Date.UTC(Number(year2), months.indexOf(month), Number(day), Number(hour), Number(minute), Number(second), fraction ? Math.round(parseFloat(`0.${fraction}`) * 1e3) : 0);
|
|
10647
10647
|
range(day, 1, 31);
|
|
10648
10648
|
range(hour, 0, 23);
|
|
10649
10649
|
range(minute, 0, 59);
|
|
10650
10650
|
range(second, 0, 60);
|
|
10651
|
-
const date6 = new Date(
|
|
10651
|
+
const date6 = new Date(timestamp3);
|
|
10652
10652
|
date6.setUTCFullYear(Number(year2));
|
|
10653
10653
|
return date6;
|
|
10654
10654
|
}
|
|
@@ -17638,14 +17638,14 @@ var init_DefaultRateLimiter = __esm({
|
|
|
17638
17638
|
this.availableTokens = this.availableTokens - amount;
|
|
17639
17639
|
}
|
|
17640
17640
|
refillTokenBucket() {
|
|
17641
|
-
const
|
|
17641
|
+
const timestamp3 = this.getCurrentTimeInSeconds();
|
|
17642
17642
|
if (!this.lastTimestamp) {
|
|
17643
|
-
this.lastTimestamp =
|
|
17643
|
+
this.lastTimestamp = timestamp3;
|
|
17644
17644
|
return;
|
|
17645
17645
|
}
|
|
17646
|
-
const fillAmount = (
|
|
17646
|
+
const fillAmount = (timestamp3 - this.lastTimestamp) * this.fillRate;
|
|
17647
17647
|
this.availableTokens = Math.min(this.maxCapacity, this.availableTokens + fillAmount);
|
|
17648
|
-
this.lastTimestamp =
|
|
17648
|
+
this.lastTimestamp = timestamp3;
|
|
17649
17649
|
}
|
|
17650
17650
|
calculateTimeWindow() {
|
|
17651
17651
|
this.timeWindow = this.getPrecise(Math.pow(this.lastMaxRate * (1 - this.beta) / this.scaleConstant, 1 / 3));
|
|
@@ -17653,8 +17653,8 @@ var init_DefaultRateLimiter = __esm({
|
|
|
17653
17653
|
cubicThrottle(rateToUse) {
|
|
17654
17654
|
return this.getPrecise(rateToUse * this.beta);
|
|
17655
17655
|
}
|
|
17656
|
-
cubicSuccess(
|
|
17657
|
-
return this.getPrecise(this.scaleConstant * Math.pow(
|
|
17656
|
+
cubicSuccess(timestamp3) {
|
|
17657
|
+
return this.getPrecise(this.scaleConstant * Math.pow(timestamp3 - this.lastThrottleTime - this.timeWindow, 3) + this.lastMaxRate);
|
|
17658
17658
|
}
|
|
17659
17659
|
enableTokenBucket() {
|
|
17660
17660
|
this.enabled = true;
|
|
@@ -49137,8 +49137,8 @@ var handle = (app, { isContentTypeBinary } = { isContentTypeBinary: void 0 }) =>
|
|
|
49137
49137
|
requestContext = getRequestContext(event);
|
|
49138
49138
|
} catch (error52) {
|
|
49139
49139
|
console.error("Error processing request:", error52);
|
|
49140
|
-
const
|
|
49141
|
-
return processor.createResult(event,
|
|
49140
|
+
const errorResponse3 = error52 instanceof TypeError ? new Response("Invalid request", { status: 400 }) : new Response("Internal Server Error", { status: 500 });
|
|
49141
|
+
return processor.createResult(event, errorResponse3, { isContentTypeBinary });
|
|
49142
49142
|
}
|
|
49143
49143
|
const res = await app.fetch(req, {
|
|
49144
49144
|
event,
|
|
@@ -64040,14 +64040,25 @@ var githubActionsSourceSchema = external_exports.looseObject({
|
|
|
64040
64040
|
branch: external_exports.string().min(1).optional(),
|
|
64041
64041
|
...sourceAuthenticationSchema
|
|
64042
64042
|
}).superRefine(exactlyOneGithubAuthenticationMode);
|
|
64043
|
+
var azureDevOpsSourceSchema = external_exports.looseObject({
|
|
64044
|
+
type: external_exports.literal("azure-devops"),
|
|
64045
|
+
/** Azure DevOps organization name, used as one URL path segment. */
|
|
64046
|
+
organization: external_exports.string().regex(/^[^/\s]+$/, "must be an organization name"),
|
|
64047
|
+
project: external_exports.string().min(1),
|
|
64048
|
+
/** The branch whose build health the dashboard represents. */
|
|
64049
|
+
branch: external_exports.string().min(1).optional(),
|
|
64050
|
+
/** Azure DevOps Build API access is authenticated with a read-scoped PAT. */
|
|
64051
|
+
token_env: external_exports.string().min(1)
|
|
64052
|
+
});
|
|
64043
64053
|
var sourceSchema = external_exports.looseObject({ type: external_exports.string().min(1), ...sourceAuthenticationSchema }).superRefine(exactlyOneGithubAuthenticationMode);
|
|
64044
64054
|
function credentialEnvironmentNames(source) {
|
|
64055
|
+
const githubApp = githubAppSchema.safeParse(source.github_app);
|
|
64045
64056
|
return [
|
|
64046
64057
|
...source.token_env ? [source.token_env] : [],
|
|
64047
|
-
...
|
|
64048
|
-
|
|
64049
|
-
|
|
64050
|
-
|
|
64058
|
+
...githubApp.success ? [
|
|
64059
|
+
githubApp.data.app_id_env,
|
|
64060
|
+
githubApp.data.private_key_env,
|
|
64061
|
+
githubApp.data.installation_id_env
|
|
64051
64062
|
] : []
|
|
64052
64063
|
];
|
|
64053
64064
|
}
|
|
@@ -64085,6 +64096,33 @@ var boardConfigSchema = external_exports.object({
|
|
|
64085
64096
|
sources: external_exports.record(external_exports.string().min(1), sourceSchema).default({}),
|
|
64086
64097
|
boards: external_exports.record(external_exports.string().min(1), boardSchema),
|
|
64087
64098
|
auth: authSchema.optional()
|
|
64099
|
+
}).superRefine((config2, ctx) => {
|
|
64100
|
+
for (const [sourceName, source] of Object.entries(config2.sources)) {
|
|
64101
|
+
if (source.type !== "azure-devops") continue;
|
|
64102
|
+
const parsedSource = azureDevOpsSourceSchema.safeParse(source);
|
|
64103
|
+
if (!parsedSource.success) {
|
|
64104
|
+
for (const issue2 of parsedSource.error.issues) {
|
|
64105
|
+
ctx.addIssue({
|
|
64106
|
+
code: "custom",
|
|
64107
|
+
path: ["sources", sourceName, ...issue2.path],
|
|
64108
|
+
message: issue2.message
|
|
64109
|
+
});
|
|
64110
|
+
}
|
|
64111
|
+
}
|
|
64112
|
+
}
|
|
64113
|
+
for (const [boardName, board] of Object.entries(config2.boards)) {
|
|
64114
|
+
board.panels.forEach((panel, panelIndex) => {
|
|
64115
|
+
const source = panel.source ? config2.sources[panel.source] : void 0;
|
|
64116
|
+
if (panel.type !== "pipeline-status" || source?.type !== "azure-devops") return;
|
|
64117
|
+
if (typeof panel.pipeline !== "number" || !Number.isInteger(panel.pipeline) || panel.pipeline <= 0) {
|
|
64118
|
+
ctx.addIssue({
|
|
64119
|
+
code: "custom",
|
|
64120
|
+
path: ["boards", boardName, "panels", panelIndex, "pipeline"],
|
|
64121
|
+
message: "Azure DevOps pipeline-status panels require a positive numeric pipeline definition id"
|
|
64122
|
+
});
|
|
64123
|
+
}
|
|
64124
|
+
});
|
|
64125
|
+
}
|
|
64088
64126
|
});
|
|
64089
64127
|
|
|
64090
64128
|
// packages/shared/src/board-config-modeline.ts
|
|
@@ -64129,15 +64167,13 @@ var clientEnvSchema = external_exports.object({
|
|
|
64129
64167
|
proxyPath: external_exports.string().min(1),
|
|
64130
64168
|
/** Which board this is, resolved server-side so the client parses no URLs. */
|
|
64131
64169
|
board: external_exports.string().min(1),
|
|
64132
|
-
/** The client version being served, so two published versions are visibly distinguishable. */
|
|
64133
|
-
clientVersion: external_exports.string().min(1),
|
|
64134
64170
|
/** Omitted entirely when unauthenticated — presence is what turns auth on. */
|
|
64135
64171
|
auth: external_exports.object({
|
|
64136
64172
|
issuer: external_exports.string().min(1),
|
|
64137
64173
|
clientId: external_exports.string().min(1).optional()
|
|
64138
64174
|
}).optional()
|
|
64139
64175
|
});
|
|
64140
|
-
var clientIdentitySchema = clientEnvSchema.pick({ assetPath: true
|
|
64176
|
+
var clientIdentitySchema = clientEnvSchema.pick({ assetPath: true });
|
|
64141
64177
|
|
|
64142
64178
|
// packages/shared/src/envelope.ts
|
|
64143
64179
|
var errorKindSchema = external_exports.enum([
|
|
@@ -64211,7 +64247,32 @@ var pullRequestHealthSchema = external_exports.object({
|
|
|
64211
64247
|
status: pipelineStatusSchema.shape.status,
|
|
64212
64248
|
summary: external_exports.string().min(1),
|
|
64213
64249
|
workflows: external_exports.array(pullRequestHealthItemSchema),
|
|
64214
|
-
pullRequests: external_exports.array(pullRequestHealthItemSchema)
|
|
64250
|
+
pullRequests: external_exports.array(pullRequestHealthItemSchema),
|
|
64251
|
+
/** Missing component reads remain visible even when the evidence we did get is reassuring. */
|
|
64252
|
+
incompleteObservations: external_exports.array(external_exports.object({ label: external_exports.string().min(1), message: external_exports.string().min(1) })).optional(),
|
|
64253
|
+
/** The latest component reading, disclosed beside the oldest aggregate evidence. */
|
|
64254
|
+
newestObservedAt: external_exports.iso.datetime().optional()
|
|
64255
|
+
});
|
|
64256
|
+
var pullRequestCandidateSchema = external_exports.object({
|
|
64257
|
+
number: external_exports.number().int().positive(),
|
|
64258
|
+
branch: external_exports.string().min(1),
|
|
64259
|
+
link: external_exports.url()
|
|
64260
|
+
});
|
|
64261
|
+
var pullRequestCandidatesSchema = external_exports.object({
|
|
64262
|
+
type: external_exports.literal("pull-request-candidates"),
|
|
64263
|
+
pullRequests: external_exports.array(pullRequestCandidateSchema),
|
|
64264
|
+
/** GitHub's first page is a deliberate bounded observation, not proof that no later PR exists. */
|
|
64265
|
+
truncated: external_exports.boolean().optional()
|
|
64266
|
+
});
|
|
64267
|
+
var pullRequestWorkflowObservationSchema = external_exports.object({
|
|
64268
|
+
type: external_exports.literal("pull-request-workflow"),
|
|
64269
|
+
workflow: external_exports.string().min(1),
|
|
64270
|
+
item: pullRequestHealthItemSchema
|
|
64271
|
+
});
|
|
64272
|
+
var pullRequestBuildObservationSchema = external_exports.object({
|
|
64273
|
+
type: external_exports.literal("pull-request-build"),
|
|
64274
|
+
branch: external_exports.string().min(1),
|
|
64275
|
+
item: pullRequestHealthItemSchema
|
|
64215
64276
|
});
|
|
64216
64277
|
var httpValueSchema = external_exports.object({
|
|
64217
64278
|
type: external_exports.literal("http-value"),
|
|
@@ -66400,6 +66461,275 @@ var Hono2 = class extends Hono {
|
|
|
66400
66461
|
// packages/server/src/app.ts
|
|
66401
66462
|
var import_yaml = __toESM(require_dist(), 1);
|
|
66402
66463
|
|
|
66464
|
+
// packages/server/src/upstream.ts
|
|
66465
|
+
function forwardValidators(requestHeaders, upstreamHeaders) {
|
|
66466
|
+
for (const name of ["if-none-match", "if-modified-since"]) {
|
|
66467
|
+
const value = requestHeaders.get(name);
|
|
66468
|
+
if (value) upstreamHeaders.set(name, value);
|
|
66469
|
+
}
|
|
66470
|
+
}
|
|
66471
|
+
function observedAt(upstreamDate) {
|
|
66472
|
+
const parsed = upstreamDate ? new Date(upstreamDate) : void 0;
|
|
66473
|
+
return parsed && !Number.isNaN(parsed.valueOf()) ? parsed.toISOString() : (/* @__PURE__ */ new Date()).toISOString();
|
|
66474
|
+
}
|
|
66475
|
+
function upstreamErrorEnvelope(args) {
|
|
66476
|
+
return {
|
|
66477
|
+
panelId: args.panelId,
|
|
66478
|
+
state: "error",
|
|
66479
|
+
observedAt: observedAt(args.upstreamDate),
|
|
66480
|
+
link: args.link,
|
|
66481
|
+
error: {
|
|
66482
|
+
kind: args.kind,
|
|
66483
|
+
message: args.error instanceof Error ? args.error.message : String(args.error)
|
|
66484
|
+
}
|
|
66485
|
+
};
|
|
66486
|
+
}
|
|
66487
|
+
function upstreamErrorResponse(envelope) {
|
|
66488
|
+
return new Response(JSON.stringify(envelope), { status: 200 });
|
|
66489
|
+
}
|
|
66490
|
+
function upstreamErrorKind(status) {
|
|
66491
|
+
if (status === 401 || status === 403) return "unauthorized";
|
|
66492
|
+
if (status === 404) return "not-found";
|
|
66493
|
+
return "upstream-error";
|
|
66494
|
+
}
|
|
66495
|
+
async function adapterRouteResponse(result) {
|
|
66496
|
+
const headers = passthroughHeaders(result.response.headers);
|
|
66497
|
+
if (result.response.status === 304) return new Response(null, { status: 304, headers });
|
|
66498
|
+
const envelope = result.envelope ?? JSON.parse(await result.response.text());
|
|
66499
|
+
headers.set("content-type", "application/json; charset=utf-8");
|
|
66500
|
+
return new Response(JSON.stringify(envelope), { status: 200, headers });
|
|
66501
|
+
}
|
|
66502
|
+
function passthroughHeaders(upstream) {
|
|
66503
|
+
const headers = new Headers();
|
|
66504
|
+
for (const name of ["cache-control", "etag", "last-modified", "date", "vary"]) {
|
|
66505
|
+
const value = upstream.get(name);
|
|
66506
|
+
if (value) headers.set(name, value);
|
|
66507
|
+
}
|
|
66508
|
+
return headers;
|
|
66509
|
+
}
|
|
66510
|
+
|
|
66511
|
+
// packages/server/src/adapters/azure-devops.ts
|
|
66512
|
+
var pipelinePanelSchema = external_exports.object({
|
|
66513
|
+
id: external_exports.string().min(1),
|
|
66514
|
+
type: external_exports.literal("pipeline-status"),
|
|
66515
|
+
source: external_exports.string().min(1),
|
|
66516
|
+
pipeline: external_exports.number().int().positive()
|
|
66517
|
+
});
|
|
66518
|
+
var buildSchema = external_exports.object({
|
|
66519
|
+
id: external_exports.number().int().positive(),
|
|
66520
|
+
buildNumber: external_exports.string().min(1),
|
|
66521
|
+
status: external_exports.string().nullable().optional(),
|
|
66522
|
+
result: external_exports.string().nullable().optional(),
|
|
66523
|
+
sourceBranch: external_exports.string().min(1).nullable().optional(),
|
|
66524
|
+
startTime: external_exports.string().nullable().optional(),
|
|
66525
|
+
finishTime: external_exports.string().nullable().optional(),
|
|
66526
|
+
lastChangedDate: external_exports.string().nullable().optional()
|
|
66527
|
+
});
|
|
66528
|
+
var buildsSchema = external_exports.object({ value: external_exports.array(buildSchema) });
|
|
66529
|
+
var timelineSchema = external_exports.object({
|
|
66530
|
+
records: external_exports.array(
|
|
66531
|
+
external_exports.object({
|
|
66532
|
+
id: external_exports.string().min(1),
|
|
66533
|
+
parentId: external_exports.string().min(1).nullable().optional(),
|
|
66534
|
+
type: external_exports.string().min(1),
|
|
66535
|
+
name: external_exports.string().min(1),
|
|
66536
|
+
state: external_exports.string().nullable().optional()
|
|
66537
|
+
})
|
|
66538
|
+
)
|
|
66539
|
+
});
|
|
66540
|
+
function permittedAzureDevOpsCalls(panel, source) {
|
|
66541
|
+
const parsedPanel = pipelinePanelSchema.parse(panel);
|
|
66542
|
+
const parsedSource = azureDevOpsSourceSchema.parse(source);
|
|
66543
|
+
return [buildsCall(parsedPanel.pipeline, parsedSource)];
|
|
66544
|
+
}
|
|
66545
|
+
async function fetchAzureDevOpsPipeline(args) {
|
|
66546
|
+
const panel = pipelinePanelSchema.parse(args.panel);
|
|
66547
|
+
const source = azureDevOpsSourceSchema.parse(args.source);
|
|
66548
|
+
const token = args.credentials.get(source.token_env);
|
|
66549
|
+
if (!token) {
|
|
66550
|
+
return {
|
|
66551
|
+
response: errorResponse(
|
|
66552
|
+
errorEnvelope(
|
|
66553
|
+
panel.id,
|
|
66554
|
+
"unauthorized",
|
|
66555
|
+
`Credential ${source.token_env} is not available.`,
|
|
66556
|
+
sourceLink(panel.pipeline, source)
|
|
66557
|
+
)
|
|
66558
|
+
)
|
|
66559
|
+
};
|
|
66560
|
+
}
|
|
66561
|
+
const call = buildsCall(panel.pipeline, source);
|
|
66562
|
+
copyValidators(args.requestHeaders, call.headers);
|
|
66563
|
+
call.headers.set("authorization", `Basic ${btoa(`:${token}`)}`);
|
|
66564
|
+
let upstream;
|
|
66565
|
+
try {
|
|
66566
|
+
upstream = await args.fetcher(call.url, { headers: call.headers });
|
|
66567
|
+
} catch (error52) {
|
|
66568
|
+
return {
|
|
66569
|
+
response: errorResponse(
|
|
66570
|
+
errorEnvelope(panel.id, "unreachable", error52, sourceLink(panel.pipeline, source))
|
|
66571
|
+
)
|
|
66572
|
+
};
|
|
66573
|
+
}
|
|
66574
|
+
if (upstream.status === 304) return { response: upstream };
|
|
66575
|
+
if (!upstream.ok) {
|
|
66576
|
+
return {
|
|
66577
|
+
response: errorResponse(
|
|
66578
|
+
errorEnvelope(
|
|
66579
|
+
panel.id,
|
|
66580
|
+
errorKind(upstream.status),
|
|
66581
|
+
`${upstream.status} ${upstream.statusText}`,
|
|
66582
|
+
sourceLink(panel.pipeline, source),
|
|
66583
|
+
observedAt2(upstream.headers.get("date"))
|
|
66584
|
+
)
|
|
66585
|
+
)
|
|
66586
|
+
};
|
|
66587
|
+
}
|
|
66588
|
+
try {
|
|
66589
|
+
const build = buildsSchema.parse(await upstream.json()).value[0];
|
|
66590
|
+
if (!build) {
|
|
66591
|
+
return {
|
|
66592
|
+
response: errorResponse(
|
|
66593
|
+
errorEnvelope(
|
|
66594
|
+
panel.id,
|
|
66595
|
+
"no-runs",
|
|
66596
|
+
source.branch ? `No builds found for branch "${source.branch}". Check the source's branch setting.` : "No builds found.",
|
|
66597
|
+
sourceLink(panel.pipeline, source),
|
|
66598
|
+
observedAt2(upstream.headers.get("date"))
|
|
66599
|
+
)
|
|
66600
|
+
)
|
|
66601
|
+
};
|
|
66602
|
+
}
|
|
66603
|
+
const signal = {
|
|
66604
|
+
type: "pipeline-status",
|
|
66605
|
+
status: normalizeStatus(build.status, build.result),
|
|
66606
|
+
rawStatus: build.result ?? build.status ?? "unknown",
|
|
66607
|
+
name: build.buildNumber,
|
|
66608
|
+
...build.sourceBranch ?? source.branch ? { branch: build.sourceBranch ?? source.branch } : {},
|
|
66609
|
+
...timestamp(build.startTime) ? { runStartedAt: timestamp(build.startTime) } : {},
|
|
66610
|
+
...timestamp(build.lastChangedDate) ? { sourceUpdatedAt: timestamp(build.lastChangedDate) } : {},
|
|
66611
|
+
sourceRunId: String(build.id),
|
|
66612
|
+
...completedBuildDuration(build)
|
|
66613
|
+
};
|
|
66614
|
+
if (signal.status === "running") {
|
|
66615
|
+
const activity = await activeAzureDevOpsActivity({
|
|
66616
|
+
buildId: build.id,
|
|
66617
|
+
source,
|
|
66618
|
+
fetcher: args.fetcher,
|
|
66619
|
+
authorization: call.headers.get("authorization") ?? ""
|
|
66620
|
+
});
|
|
66621
|
+
if (activity) signal.activity = activity;
|
|
66622
|
+
}
|
|
66623
|
+
return {
|
|
66624
|
+
envelope: {
|
|
66625
|
+
panelId: panel.id,
|
|
66626
|
+
state: "ok",
|
|
66627
|
+
observedAt: observedAt2(upstream.headers.get("date")),
|
|
66628
|
+
link: buildLink(build.id, source),
|
|
66629
|
+
signal
|
|
66630
|
+
},
|
|
66631
|
+
response: upstream
|
|
66632
|
+
};
|
|
66633
|
+
} catch (error52) {
|
|
66634
|
+
return {
|
|
66635
|
+
response: errorResponse(
|
|
66636
|
+
errorEnvelope(
|
|
66637
|
+
panel.id,
|
|
66638
|
+
"upstream-error",
|
|
66639
|
+
error52,
|
|
66640
|
+
sourceLink(panel.pipeline, source),
|
|
66641
|
+
observedAt2(upstream.headers.get("date"))
|
|
66642
|
+
)
|
|
66643
|
+
)
|
|
66644
|
+
};
|
|
66645
|
+
}
|
|
66646
|
+
}
|
|
66647
|
+
function buildsCall(definitionId, source) {
|
|
66648
|
+
const url2 = apiUrl(source, "build/builds");
|
|
66649
|
+
url2.searchParams.set("definitions", String(definitionId));
|
|
66650
|
+
if (source.branch) url2.searchParams.set("branchName", adoBranch(source.branch));
|
|
66651
|
+
url2.searchParams.set("queryOrder", "queueTimeDescending");
|
|
66652
|
+
url2.searchParams.set("$top", "1");
|
|
66653
|
+
return { url: url2.toString(), headers: new Headers({ accept: "application/json" }) };
|
|
66654
|
+
}
|
|
66655
|
+
function timelineCall(buildId, source) {
|
|
66656
|
+
return {
|
|
66657
|
+
url: apiUrl(source, `build/builds/${buildId}/timeline`).toString(),
|
|
66658
|
+
headers: new Headers({ accept: "application/json" })
|
|
66659
|
+
};
|
|
66660
|
+
}
|
|
66661
|
+
function apiUrl(source, suffix) {
|
|
66662
|
+
const url2 = new URL(
|
|
66663
|
+
`https://dev.azure.com/${encodeURIComponent(source.organization)}/${encodeURIComponent(source.project)}/_apis/${suffix}`
|
|
66664
|
+
);
|
|
66665
|
+
url2.searchParams.set("api-version", "7.1");
|
|
66666
|
+
return url2;
|
|
66667
|
+
}
|
|
66668
|
+
function adoBranch(branch) {
|
|
66669
|
+
return branch.startsWith("refs/") ? branch : `refs/heads/${branch}`;
|
|
66670
|
+
}
|
|
66671
|
+
async function activeAzureDevOpsActivity(args) {
|
|
66672
|
+
const call = timelineCall(args.buildId, args.source);
|
|
66673
|
+
call.headers.set("authorization", args.authorization);
|
|
66674
|
+
try {
|
|
66675
|
+
const response = await args.fetcher(call.url, { headers: call.headers });
|
|
66676
|
+
if (!response.ok) return void 0;
|
|
66677
|
+
const records = timelineSchema.parse(await response.json()).records;
|
|
66678
|
+
const active = records.find((record2) => record2.state === "inProgress");
|
|
66679
|
+
if (!active) return void 0;
|
|
66680
|
+
const parent = active.parentId ? records.find((record2) => record2.id === active.parentId) : void 0;
|
|
66681
|
+
const kind = active.type.toLowerCase();
|
|
66682
|
+
return {
|
|
66683
|
+
kind: kind === "stage" ? "stage" : kind === "job" ? "job" : "step",
|
|
66684
|
+
name: active.name,
|
|
66685
|
+
...parent ? { parent: parent.name } : {}
|
|
66686
|
+
};
|
|
66687
|
+
} catch {
|
|
66688
|
+
return void 0;
|
|
66689
|
+
}
|
|
66690
|
+
}
|
|
66691
|
+
function normalizeStatus(status, result) {
|
|
66692
|
+
if (status === "notStarted" || status === "postponed" || status === "inProgress" || status === "cancelling")
|
|
66693
|
+
return "running";
|
|
66694
|
+
if (status !== "completed") return "unknown";
|
|
66695
|
+
if (result === "succeeded") return "passed";
|
|
66696
|
+
if (result === "failed") return "failed";
|
|
66697
|
+
if (result === "canceled") return "cancelled";
|
|
66698
|
+
return "unknown";
|
|
66699
|
+
}
|
|
66700
|
+
function completedBuildDuration(build) {
|
|
66701
|
+
const startedAt = timestamp(build.startTime);
|
|
66702
|
+
const finishedAt = timestamp(build.finishTime);
|
|
66703
|
+
if (!startedAt || !finishedAt) return {};
|
|
66704
|
+
const durationMs = new Date(finishedAt).valueOf() - new Date(startedAt).valueOf();
|
|
66705
|
+
return Number.isFinite(durationMs) && durationMs >= 0 ? { durationMs } : {};
|
|
66706
|
+
}
|
|
66707
|
+
function timestamp(value) {
|
|
66708
|
+
if (!value || !external_exports.iso.datetime().safeParse(value).success) return void 0;
|
|
66709
|
+
return Number.isFinite(new Date(value).valueOf()) ? value : void 0;
|
|
66710
|
+
}
|
|
66711
|
+
function copyValidators(requestHeaders, upstreamHeaders) {
|
|
66712
|
+
forwardValidators(requestHeaders, upstreamHeaders);
|
|
66713
|
+
}
|
|
66714
|
+
function buildLink(buildId, source) {
|
|
66715
|
+
return `https://dev.azure.com/${encodeURIComponent(source.organization)}/${encodeURIComponent(source.project)}/_build/results?buildId=${buildId}`;
|
|
66716
|
+
}
|
|
66717
|
+
function sourceLink(definitionId, source) {
|
|
66718
|
+
return `https://dev.azure.com/${encodeURIComponent(source.organization)}/${encodeURIComponent(source.project)}/_build?definitionId=${definitionId}`;
|
|
66719
|
+
}
|
|
66720
|
+
function errorResponse(envelope) {
|
|
66721
|
+
return upstreamErrorResponse(envelope);
|
|
66722
|
+
}
|
|
66723
|
+
function errorEnvelope(panelId, kind, error52, link, date6) {
|
|
66724
|
+
return upstreamErrorEnvelope({ panelId, kind, error: error52, link, upstreamDate: date6 });
|
|
66725
|
+
}
|
|
66726
|
+
function errorKind(status) {
|
|
66727
|
+
return upstreamErrorKind(status);
|
|
66728
|
+
}
|
|
66729
|
+
function observedAt2(value) {
|
|
66730
|
+
return observedAt(value);
|
|
66731
|
+
}
|
|
66732
|
+
|
|
66403
66733
|
// packages/server/src/credentials.ts
|
|
66404
66734
|
var import_client_secrets_manager = __toESM(require_dist_cjs16(), 1);
|
|
66405
66735
|
var import_client_ssm = __toESM(require_dist_cjs17(), 1);
|
|
@@ -66509,10 +66839,7 @@ function createGithubClient(credentials, now = Date.now) {
|
|
|
66509
66839
|
}
|
|
66510
66840
|
function githubHeaders(requestHeaders) {
|
|
66511
66841
|
const headers = new Headers({ accept: "application/vnd.github+json" });
|
|
66512
|
-
|
|
66513
|
-
const value = requestHeaders.get(name);
|
|
66514
|
-
if (value) headers.set(name, value);
|
|
66515
|
-
}
|
|
66842
|
+
forwardValidators(requestHeaders, headers);
|
|
66516
66843
|
return headers;
|
|
66517
66844
|
}
|
|
66518
66845
|
async function exchangeInstallationToken(args) {
|
|
@@ -66565,7 +66892,7 @@ function base64url3(value) {
|
|
|
66565
66892
|
}
|
|
66566
66893
|
|
|
66567
66894
|
// packages/server/src/adapters/github-actions.ts
|
|
66568
|
-
var
|
|
66895
|
+
var pipelinePanelSchema2 = external_exports.object({
|
|
66569
66896
|
id: external_exports.string().min(1),
|
|
66570
66897
|
type: external_exports.literal("pipeline-status"),
|
|
66571
66898
|
source: external_exports.string().min(1),
|
|
@@ -66616,7 +66943,7 @@ var pullRequestsSchema = external_exports.array(
|
|
|
66616
66943
|
})
|
|
66617
66944
|
);
|
|
66618
66945
|
function permittedGithubActionsCalls(panel, source, _credentials) {
|
|
66619
|
-
const parsedPanel =
|
|
66946
|
+
const parsedPanel = pipelinePanelSchema2.parse(panel);
|
|
66620
66947
|
const parsedSource = githubActionsSourceSchema.parse(source);
|
|
66621
66948
|
const url2 = new URL(
|
|
66622
66949
|
`https://api.github.com/repos/${parsedSource.repo}/actions/workflows/${encodeURIComponent(parsedPanel.pipeline)}/runs`
|
|
@@ -66625,90 +66952,117 @@ function permittedGithubActionsCalls(panel, source, _credentials) {
|
|
|
66625
66952
|
url2.searchParams.set("per_page", "1");
|
|
66626
66953
|
return [{ url: url2.toString(), headers: new Headers() }];
|
|
66627
66954
|
}
|
|
66628
|
-
function
|
|
66629
|
-
const
|
|
66630
|
-
|
|
66631
|
-
|
|
66632
|
-
(
|
|
66955
|
+
function pullRequestHealthCapabilities(panel) {
|
|
66956
|
+
const parsed = pullRequestHealthPanelSchema.parse(panel);
|
|
66957
|
+
return {
|
|
66958
|
+
panel: parsed,
|
|
66959
|
+
configuredUpdateWorkflow(workflow) {
|
|
66960
|
+
return parsed.update_workflows.find((candidate) => candidate.workflow === workflow);
|
|
66961
|
+
},
|
|
66962
|
+
permitsBuildBranch(branch) {
|
|
66963
|
+
return parsed.update_workflows.some(
|
|
66964
|
+
({ branch_prefixes }) => branch_prefixes.some((prefix) => branch.startsWith(prefix))
|
|
66965
|
+
);
|
|
66966
|
+
}
|
|
66967
|
+
};
|
|
66968
|
+
}
|
|
66969
|
+
async function fetchGithubActionsPullRequestCandidates(args) {
|
|
66970
|
+
const capabilities = pullRequestHealthCapabilities(args.panel);
|
|
66971
|
+
const panel = capabilities.panel;
|
|
66972
|
+
const source = githubActionsSourceSchema.parse(args.source);
|
|
66973
|
+
return githubObservation(
|
|
66974
|
+
args,
|
|
66975
|
+
source,
|
|
66976
|
+
pullRequestsCall(source, panel.base_branch, 1),
|
|
66977
|
+
(value, observedAt4) => {
|
|
66978
|
+
const page = pullRequestsSchema.parse(value);
|
|
66979
|
+
const pullRequests = page.filter(
|
|
66980
|
+
(pullRequest) => capabilities.permitsBuildBranch(pullRequest.head.ref)
|
|
66981
|
+
);
|
|
66982
|
+
return {
|
|
66983
|
+
panelId: panel.id,
|
|
66984
|
+
state: "ok",
|
|
66985
|
+
observedAt: observedAt4,
|
|
66986
|
+
link: sourceLinkForRepository(source),
|
|
66987
|
+
signal: {
|
|
66988
|
+
type: "pull-request-candidates",
|
|
66989
|
+
pullRequests: pullRequests.map((pullRequest) => ({
|
|
66990
|
+
number: pullRequest.number,
|
|
66991
|
+
branch: pullRequest.head.ref,
|
|
66992
|
+
link: pullRequest.html_url
|
|
66993
|
+
})),
|
|
66994
|
+
...page.length === 100 ? { truncated: true } : {}
|
|
66995
|
+
}
|
|
66996
|
+
};
|
|
66997
|
+
}
|
|
66633
66998
|
);
|
|
66634
|
-
calls.push({
|
|
66635
|
-
...pullRequestsCall(parsedSource, parsedPanel.base_branch, 1)
|
|
66636
|
-
});
|
|
66637
|
-
return calls;
|
|
66638
66999
|
}
|
|
66639
|
-
async function
|
|
66640
|
-
const
|
|
67000
|
+
async function fetchGithubActionsUpdateWorkflow(args) {
|
|
67001
|
+
const capabilities = pullRequestHealthCapabilities(args.panel);
|
|
67002
|
+
const panel = capabilities.panel;
|
|
66641
67003
|
const source = githubActionsSourceSchema.parse(args.source);
|
|
67004
|
+
const configured = capabilities.configuredUpdateWorkflow(args.workflow);
|
|
67005
|
+
if (!configured) throw new Error("Unconfigured update workflow");
|
|
67006
|
+
return githubObservation(
|
|
67007
|
+
args,
|
|
67008
|
+
source,
|
|
67009
|
+
githubRunsCall(source, configured.workflow, void 0, void 0, 100),
|
|
67010
|
+
(value, observedAt4) => {
|
|
67011
|
+
const run = runsSchema.parse(value).workflow_runs.find((candidate) => {
|
|
67012
|
+
const branch = candidate.head_branch;
|
|
67013
|
+
return typeof branch === "string" && configured.branch_prefixes.some((prefix) => branch.startsWith(prefix));
|
|
67014
|
+
});
|
|
67015
|
+
return {
|
|
67016
|
+
panelId: panel.id,
|
|
67017
|
+
state: "ok",
|
|
67018
|
+
observedAt: observedAt4,
|
|
67019
|
+
link: sourceLinkForRepository(source),
|
|
67020
|
+
signal: {
|
|
67021
|
+
type: "pull-request-workflow",
|
|
67022
|
+
workflow: configured.workflow,
|
|
67023
|
+
item: healthItem(configured.workflow, run, `Update workflow ${configured.workflow}`)
|
|
67024
|
+
}
|
|
67025
|
+
};
|
|
67026
|
+
}
|
|
67027
|
+
);
|
|
67028
|
+
}
|
|
67029
|
+
async function fetchGithubActionsPullRequestBuild(args) {
|
|
67030
|
+
const capabilities = pullRequestHealthCapabilities(args.panel);
|
|
67031
|
+
const panel = capabilities.panel;
|
|
67032
|
+
const source = githubActionsSourceSchema.parse(args.source);
|
|
67033
|
+
if (!capabilities.permitsBuildBranch(args.branch))
|
|
67034
|
+
throw new Error("Unpermitted pull request branch");
|
|
67035
|
+
return githubObservation(
|
|
67036
|
+
args,
|
|
67037
|
+
source,
|
|
67038
|
+
githubRunsCall(source, panel.build_workflow, args.branch, "pull_request"),
|
|
67039
|
+
(value, observedAt4) => {
|
|
67040
|
+
const run = runsSchema.parse(value).workflow_runs[0];
|
|
67041
|
+
return {
|
|
67042
|
+
panelId: panel.id,
|
|
67043
|
+
state: "ok",
|
|
67044
|
+
observedAt: observedAt4,
|
|
67045
|
+
link: sourceLinkForRepository(source),
|
|
67046
|
+
signal: {
|
|
67047
|
+
type: "pull-request-build",
|
|
67048
|
+
branch: args.branch,
|
|
67049
|
+
item: healthItem(args.branch, run, args.branch)
|
|
67050
|
+
}
|
|
67051
|
+
};
|
|
67052
|
+
}
|
|
67053
|
+
);
|
|
67054
|
+
}
|
|
67055
|
+
async function githubObservation(args, source, call, normalize) {
|
|
67056
|
+
let upstream;
|
|
66642
67057
|
try {
|
|
66643
|
-
|
|
66644
|
-
panel.update_workflows.map(async ({ workflow, branch_prefixes }) => ({
|
|
66645
|
-
workflow,
|
|
66646
|
-
run: await latestRun({
|
|
66647
|
-
source,
|
|
66648
|
-
workflow,
|
|
66649
|
-
branchPrefixes: branch_prefixes,
|
|
66650
|
-
requestHeaders: args.requestHeaders,
|
|
66651
|
-
fetcher: args.fetcher,
|
|
66652
|
-
githubClient: githubClientFor(args)
|
|
66653
|
-
})
|
|
66654
|
-
}))
|
|
66655
|
-
);
|
|
66656
|
-
const pullRequests = await openPullRequests({
|
|
66657
|
-
source,
|
|
66658
|
-
baseBranch: panel.base_branch,
|
|
66659
|
-
requestHeaders: args.requestHeaders,
|
|
66660
|
-
fetcher: args.fetcher,
|
|
66661
|
-
githubClient: githubClientFor(args)
|
|
66662
|
-
});
|
|
66663
|
-
const matching = pullRequests.filter(
|
|
66664
|
-
(pullRequest) => panel.update_workflows.some(
|
|
66665
|
-
({ branch_prefixes }) => branch_prefixes.some((prefix) => pullRequest.head.ref.startsWith(prefix))
|
|
66666
|
-
)
|
|
66667
|
-
);
|
|
66668
|
-
const pullRequestResults = await Promise.all(
|
|
66669
|
-
matching.map(async (pullRequest) => ({
|
|
66670
|
-
pullRequest,
|
|
66671
|
-
run: await latestRun({
|
|
66672
|
-
source,
|
|
66673
|
-
workflow: panel.build_workflow,
|
|
66674
|
-
branch: pullRequest.head.ref,
|
|
66675
|
-
event: "pull_request",
|
|
66676
|
-
requestHeaders: args.requestHeaders,
|
|
66677
|
-
fetcher: args.fetcher,
|
|
66678
|
-
githubClient: githubClientFor(args)
|
|
66679
|
-
})
|
|
66680
|
-
}))
|
|
66681
|
-
);
|
|
66682
|
-
const workflows = workflowResults.map(
|
|
66683
|
-
({ workflow, run }) => healthItem(workflow, run, `Update workflow ${workflow}`)
|
|
66684
|
-
);
|
|
66685
|
-
const pullRequestItems = pullRequestResults.map(
|
|
66686
|
-
({ pullRequest, run }) => healthItem(`PR #${pullRequest.number}`, run, pullRequest.head.ref, pullRequest.html_url)
|
|
66687
|
-
);
|
|
66688
|
-
const allItems = [...workflows, ...pullRequestItems];
|
|
66689
|
-
const status = aggregateStatus(allItems.map((item) => item.status));
|
|
66690
|
-
const summary = summarize(status, workflows, pullRequestItems);
|
|
66691
|
-
const envelope = {
|
|
66692
|
-
panelId: panel.id,
|
|
66693
|
-
state: "ok",
|
|
66694
|
-
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
66695
|
-
link: sourceLinkForRepository(source),
|
|
66696
|
-
signal: {
|
|
66697
|
-
type: "pull-request-health",
|
|
66698
|
-
status,
|
|
66699
|
-
summary,
|
|
66700
|
-
workflows,
|
|
66701
|
-
pullRequests: pullRequestItems
|
|
66702
|
-
}
|
|
66703
|
-
};
|
|
66704
|
-
return { envelope, response: new Response(null, { status: 200 }) };
|
|
67058
|
+
upstream = await githubFetch(call, { ...args, source, githubClient: githubClientFor(args) });
|
|
66705
67059
|
} catch (error52) {
|
|
66706
67060
|
return {
|
|
66707
67061
|
response: new Response(
|
|
66708
67062
|
JSON.stringify(
|
|
66709
|
-
|
|
66710
|
-
panel.id,
|
|
66711
|
-
error52 instanceof GithubAuthenticationError ? "unauthorized" : "
|
|
67063
|
+
errorEnvelope2(
|
|
67064
|
+
args.panel.id,
|
|
67065
|
+
error52 instanceof GithubAuthenticationError ? "unauthorized" : "unreachable",
|
|
66712
67066
|
error52,
|
|
66713
67067
|
sourceLinkForRepository(source)
|
|
66714
67068
|
)
|
|
@@ -66717,34 +67071,42 @@ async function fetchGithubActionsPullRequestHealth(args) {
|
|
|
66717
67071
|
)
|
|
66718
67072
|
};
|
|
66719
67073
|
}
|
|
66720
|
-
}
|
|
66721
|
-
|
|
66722
|
-
|
|
66723
|
-
|
|
66724
|
-
|
|
66725
|
-
|
|
66726
|
-
|
|
66727
|
-
|
|
66728
|
-
|
|
66729
|
-
|
|
66730
|
-
|
|
66731
|
-
|
|
66732
|
-
|
|
66733
|
-
|
|
66734
|
-
|
|
66735
|
-
|
|
66736
|
-
|
|
66737
|
-
|
|
66738
|
-
|
|
66739
|
-
|
|
66740
|
-
|
|
66741
|
-
|
|
66742
|
-
|
|
66743
|
-
|
|
66744
|
-
|
|
66745
|
-
|
|
66746
|
-
|
|
66747
|
-
|
|
67074
|
+
if (upstream.status === 304) return { response: upstream };
|
|
67075
|
+
if (!upstream.ok)
|
|
67076
|
+
return {
|
|
67077
|
+
response: new Response(
|
|
67078
|
+
JSON.stringify(
|
|
67079
|
+
errorEnvelope2(
|
|
67080
|
+
args.panel.id,
|
|
67081
|
+
errorKind2(upstream.status),
|
|
67082
|
+
`${upstream.status} ${upstream.statusText}`,
|
|
67083
|
+
sourceLinkForRepository(source),
|
|
67084
|
+
observedAt3(upstream.headers.get("date"))
|
|
67085
|
+
)
|
|
67086
|
+
),
|
|
67087
|
+
{ status: 200 }
|
|
67088
|
+
)
|
|
67089
|
+
};
|
|
67090
|
+
try {
|
|
67091
|
+
return {
|
|
67092
|
+
envelope: normalize(await upstream.json(), observedAt3(upstream.headers.get("date"))),
|
|
67093
|
+
response: upstream
|
|
67094
|
+
};
|
|
67095
|
+
} catch (error52) {
|
|
67096
|
+
return {
|
|
67097
|
+
response: new Response(
|
|
67098
|
+
JSON.stringify(
|
|
67099
|
+
errorEnvelope2(
|
|
67100
|
+
args.panel.id,
|
|
67101
|
+
"upstream-error",
|
|
67102
|
+
error52,
|
|
67103
|
+
sourceLinkForRepository(source),
|
|
67104
|
+
observedAt3(upstream.headers.get("date"))
|
|
67105
|
+
)
|
|
67106
|
+
),
|
|
67107
|
+
{ status: 200 }
|
|
67108
|
+
)
|
|
67109
|
+
};
|
|
66748
67110
|
}
|
|
66749
67111
|
}
|
|
66750
67112
|
function pullRequestsCall(source, baseBranch, page) {
|
|
@@ -66767,23 +67129,11 @@ function githubRunsCall(source, workflow, branch, event, perPage = 1) {
|
|
|
66767
67129
|
function healthItem(label, run, detail, link) {
|
|
66768
67130
|
return {
|
|
66769
67131
|
label,
|
|
66770
|
-
status: run ?
|
|
67132
|
+
status: run ? normalizeStatus2(run.status, run.conclusion) : "unknown",
|
|
66771
67133
|
detail: run ? `${detail} \xB7 ${run.conclusion ?? run.status}` : `${detail} \xB7 No run found`,
|
|
66772
67134
|
link: link ?? run?.html_url ?? null
|
|
66773
67135
|
};
|
|
66774
67136
|
}
|
|
66775
|
-
function aggregateStatus(statuses) {
|
|
66776
|
-
if (statuses.some((status) => status === "failed")) return "failed";
|
|
66777
|
-
if (statuses.some((status) => status === "running")) return "running";
|
|
66778
|
-
if (statuses.some((status) => status === "unknown")) return "unknown";
|
|
66779
|
-
if (statuses.some((status) => status === "cancelled")) return "cancelled";
|
|
66780
|
-
return "passed";
|
|
66781
|
-
}
|
|
66782
|
-
function summarize(status, workflows, pullRequests) {
|
|
66783
|
-
const failed = [...workflows, ...pullRequests].find((item) => item.status === status);
|
|
66784
|
-
if (status !== "passed" && failed) return `${failed.label}: ${failed.detail}`;
|
|
66785
|
-
return pullRequests.length === 0 ? `${workflows.length} update workflow${workflows.length === 1 ? "" : "s"} \xB7 No open update PRs` : `${workflows.length} update workflow${workflows.length === 1 ? "" : "s"} \xB7 ${pullRequests.length} open update PR${pullRequests.length === 1 ? "" : "s"}`;
|
|
66786
|
-
}
|
|
66787
67137
|
function sourceLinkForRepository(source) {
|
|
66788
67138
|
return `https://github.com/${source.repo}`;
|
|
66789
67139
|
}
|
|
@@ -66803,11 +67153,11 @@ async function fetchGithubActionsPipeline(args) {
|
|
|
66803
67153
|
return {
|
|
66804
67154
|
response: new Response(
|
|
66805
67155
|
JSON.stringify(
|
|
66806
|
-
|
|
67156
|
+
errorEnvelope2(
|
|
66807
67157
|
args.panel.id,
|
|
66808
67158
|
error52 instanceof GithubAuthenticationError ? "unauthorized" : "unreachable",
|
|
66809
67159
|
error52,
|
|
66810
|
-
|
|
67160
|
+
sourceLink2(args.panel, args.source)
|
|
66811
67161
|
)
|
|
66812
67162
|
),
|
|
66813
67163
|
{ status: 200 }
|
|
@@ -66819,12 +67169,12 @@ async function fetchGithubActionsPipeline(args) {
|
|
|
66819
67169
|
return {
|
|
66820
67170
|
response: new Response(
|
|
66821
67171
|
JSON.stringify(
|
|
66822
|
-
|
|
67172
|
+
errorEnvelope2(
|
|
66823
67173
|
args.panel.id,
|
|
66824
|
-
|
|
67174
|
+
errorKind2(upstream.status),
|
|
66825
67175
|
`${upstream.status} ${upstream.statusText}`,
|
|
66826
|
-
|
|
66827
|
-
|
|
67176
|
+
sourceLink2(args.panel, args.source),
|
|
67177
|
+
observedAt3(upstream.headers.get("date"))
|
|
66828
67178
|
)
|
|
66829
67179
|
),
|
|
66830
67180
|
{ status: 200 }
|
|
@@ -66838,12 +67188,12 @@ async function fetchGithubActionsPipeline(args) {
|
|
|
66838
67188
|
return {
|
|
66839
67189
|
response: new Response(
|
|
66840
67190
|
JSON.stringify(
|
|
66841
|
-
|
|
67191
|
+
errorEnvelope2(
|
|
66842
67192
|
args.panel.id,
|
|
66843
67193
|
"no-runs",
|
|
66844
67194
|
parsedSource.branch ? `No workflow runs found for branch "${parsedSource.branch}". Check the source's branch setting.` : "No workflow runs found.",
|
|
66845
|
-
|
|
66846
|
-
|
|
67195
|
+
sourceLink2(args.panel, args.source),
|
|
67196
|
+
observedAt3(upstream.headers.get("date"))
|
|
66847
67197
|
)
|
|
66848
67198
|
),
|
|
66849
67199
|
{ status: 200 }
|
|
@@ -66852,12 +67202,12 @@ async function fetchGithubActionsPipeline(args) {
|
|
|
66852
67202
|
}
|
|
66853
67203
|
const signal = {
|
|
66854
67204
|
type: "pipeline-status",
|
|
66855
|
-
status:
|
|
67205
|
+
status: normalizeStatus2(run.status, run.conclusion),
|
|
66856
67206
|
rawStatus: run.conclusion ?? run.status,
|
|
66857
67207
|
name: run.name,
|
|
66858
67208
|
...run.head_branch ?? parsedSource.branch ? { branch: run.head_branch ?? parsedSource.branch } : {},
|
|
66859
|
-
...
|
|
66860
|
-
...
|
|
67209
|
+
...timestamp2(run.updated_at) ? { sourceUpdatedAt: timestamp2(run.updated_at) } : {},
|
|
67210
|
+
...timestamp2(run.run_started_at) ? { runStartedAt: timestamp2(run.run_started_at) } : {},
|
|
66861
67211
|
...run.id !== void 0 ? { sourceRunId: String(run.id) } : {},
|
|
66862
67212
|
...run.status === "completed" ? completedRunDuration(run) : {}
|
|
66863
67213
|
};
|
|
@@ -66874,7 +67224,7 @@ async function fetchGithubActionsPipeline(args) {
|
|
|
66874
67224
|
const envelope = {
|
|
66875
67225
|
panelId: args.panel.id,
|
|
66876
67226
|
state: "ok",
|
|
66877
|
-
observedAt:
|
|
67227
|
+
observedAt: observedAt3(upstream.headers.get("date")),
|
|
66878
67228
|
link: run.html_url,
|
|
66879
67229
|
signal
|
|
66880
67230
|
};
|
|
@@ -66883,12 +67233,12 @@ async function fetchGithubActionsPipeline(args) {
|
|
|
66883
67233
|
return {
|
|
66884
67234
|
response: new Response(
|
|
66885
67235
|
JSON.stringify(
|
|
66886
|
-
|
|
67236
|
+
errorEnvelope2(
|
|
66887
67237
|
args.panel.id,
|
|
66888
67238
|
"upstream-error",
|
|
66889
67239
|
error52,
|
|
66890
|
-
|
|
66891
|
-
|
|
67240
|
+
sourceLink2(args.panel, args.source),
|
|
67241
|
+
observedAt3(upstream.headers.get("date"))
|
|
66892
67242
|
)
|
|
66893
67243
|
),
|
|
66894
67244
|
{ status: 200 }
|
|
@@ -66927,45 +67277,36 @@ function githubJobsCall(source, runId) {
|
|
|
66927
67277
|
return { url: url2.toString(), headers: new Headers() };
|
|
66928
67278
|
}
|
|
66929
67279
|
function completedRunDuration(run) {
|
|
66930
|
-
const startedAt =
|
|
66931
|
-
const updatedAt =
|
|
67280
|
+
const startedAt = timestamp2(run.run_started_at);
|
|
67281
|
+
const updatedAt = timestamp2(run.updated_at);
|
|
66932
67282
|
if (!startedAt || !updatedAt) return {};
|
|
66933
67283
|
const durationMs = new Date(updatedAt).valueOf() - new Date(startedAt).valueOf();
|
|
66934
67284
|
return Number.isFinite(durationMs) && durationMs >= 0 ? { durationMs } : {};
|
|
66935
67285
|
}
|
|
66936
|
-
function
|
|
67286
|
+
function timestamp2(value) {
|
|
66937
67287
|
if (!value || !external_exports.iso.datetime().safeParse(value).success) return void 0;
|
|
66938
67288
|
return Number.isFinite(new Date(value).valueOf()) ? value : void 0;
|
|
66939
67289
|
}
|
|
66940
|
-
function
|
|
67290
|
+
function normalizeStatus2(status, conclusion) {
|
|
66941
67291
|
if (status !== "completed") return "running";
|
|
66942
67292
|
if (conclusion === "success") return "passed";
|
|
66943
67293
|
if (conclusion === "failure" || conclusion === "timed_out") return "failed";
|
|
66944
67294
|
if (conclusion === "cancelled") return "cancelled";
|
|
66945
67295
|
return "unknown";
|
|
66946
67296
|
}
|
|
66947
|
-
function
|
|
66948
|
-
|
|
66949
|
-
if (status === 404) return "not-found";
|
|
66950
|
-
return "upstream-error";
|
|
67297
|
+
function errorKind2(status) {
|
|
67298
|
+
return upstreamErrorKind(status);
|
|
66951
67299
|
}
|
|
66952
|
-
function
|
|
66953
|
-
return {
|
|
66954
|
-
panelId,
|
|
66955
|
-
state: "error",
|
|
66956
|
-
observedAt: observedAt3,
|
|
66957
|
-
link,
|
|
66958
|
-
error: { kind, message: error52 instanceof Error ? error52.message : String(error52) }
|
|
66959
|
-
};
|
|
67300
|
+
function errorEnvelope2(panelId, kind, error52, link, observedAt4 = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
67301
|
+
return upstreamErrorEnvelope({ panelId, kind, error: error52, link, upstreamDate: observedAt4 });
|
|
66960
67302
|
}
|
|
66961
|
-
function
|
|
66962
|
-
const parsedPanel =
|
|
67303
|
+
function sourceLink2(panel, source) {
|
|
67304
|
+
const parsedPanel = pipelinePanelSchema2.parse(panel);
|
|
66963
67305
|
const parsedSource = githubActionsSourceSchema.parse(source);
|
|
66964
67306
|
return `https://github.com/${parsedSource.repo}/actions/workflows/${encodeURIComponent(parsedPanel.pipeline)}`;
|
|
66965
67307
|
}
|
|
66966
|
-
function
|
|
66967
|
-
|
|
66968
|
-
return parsed && !Number.isNaN(parsed.valueOf()) ? parsed.toISOString() : (/* @__PURE__ */ new Date()).toISOString();
|
|
67308
|
+
function observedAt3(value) {
|
|
67309
|
+
return observedAt(value);
|
|
66969
67310
|
}
|
|
66970
67311
|
|
|
66971
67312
|
// packages/server/src/adapters/http-value.ts
|
|
@@ -66988,22 +67329,21 @@ async function fetchHttpValue(args) {
|
|
|
66988
67329
|
const panel = httpValuePanelSchema.parse(args.panel);
|
|
66989
67330
|
const [call] = permittedHttpValueCalls(args.panel);
|
|
66990
67331
|
if (!call) throw new Error("http-value adapter declared no permitted call");
|
|
66991
|
-
|
|
66992
|
-
const value = args.requestHeaders.get(name);
|
|
66993
|
-
if (value) call.headers.set(name, value);
|
|
66994
|
-
}
|
|
67332
|
+
forwardValidators(args.requestHeaders, call.headers);
|
|
66995
67333
|
let upstream;
|
|
66996
67334
|
try {
|
|
66997
67335
|
upstream = await args.fetcher(call.url, { headers: call.headers });
|
|
66998
67336
|
} catch (error52) {
|
|
66999
|
-
return { response:
|
|
67337
|
+
return { response: errorResponse2("unreachable", error52, panel) };
|
|
67000
67338
|
}
|
|
67001
67339
|
if (upstream.status === 304) return { response: upstream };
|
|
67002
67340
|
if (!upstream.ok) {
|
|
67003
|
-
const kind = upstream.status === 401 || upstream.status === 403 ? "unauthorized" : upstream.status === 404 ? "not-found" : "upstream-error";
|
|
67004
67341
|
return {
|
|
67005
|
-
response:
|
|
67006
|
-
|
|
67342
|
+
response: errorResponse2(
|
|
67343
|
+
upstreamErrorKind(upstream.status),
|
|
67344
|
+
`${upstream.status} ${upstream.statusText}`,
|
|
67345
|
+
panel,
|
|
67346
|
+
upstream
|
|
67007
67347
|
)
|
|
67008
67348
|
};
|
|
67009
67349
|
}
|
|
@@ -67015,7 +67355,7 @@ async function fetchHttpValue(args) {
|
|
|
67015
67355
|
envelope: {
|
|
67016
67356
|
panelId: panel.id,
|
|
67017
67357
|
state: "ok",
|
|
67018
|
-
observedAt:
|
|
67358
|
+
observedAt: observedAt(upstream.headers.get("date")),
|
|
67019
67359
|
link: panel.link ?? panel.url,
|
|
67020
67360
|
signal
|
|
67021
67361
|
},
|
|
@@ -67023,7 +67363,7 @@ async function fetchHttpValue(args) {
|
|
|
67023
67363
|
};
|
|
67024
67364
|
} catch (error52) {
|
|
67025
67365
|
return {
|
|
67026
|
-
response:
|
|
67366
|
+
response: errorResponse2("upstream-error", error52, panel, upstream)
|
|
67027
67367
|
};
|
|
67028
67368
|
}
|
|
67029
67369
|
}
|
|
@@ -67050,21 +67390,16 @@ function extractJsonPath(value, path) {
|
|
|
67050
67390
|
}
|
|
67051
67391
|
return current;
|
|
67052
67392
|
}
|
|
67053
|
-
function
|
|
67054
|
-
return
|
|
67055
|
-
|
|
67056
|
-
|
|
67057
|
-
|
|
67058
|
-
|
|
67059
|
-
|
|
67060
|
-
|
|
67061
|
-
|
|
67062
|
-
|
|
67063
|
-
};
|
|
67064
|
-
}
|
|
67065
|
-
function observedAt2(value) {
|
|
67066
|
-
const parsed = value ? new Date(value) : void 0;
|
|
67067
|
-
return parsed && !Number.isNaN(parsed.valueOf()) ? parsed.toISOString() : (/* @__PURE__ */ new Date()).toISOString();
|
|
67393
|
+
function errorResponse2(kind, error52, panel, response) {
|
|
67394
|
+
return upstreamErrorResponse(
|
|
67395
|
+
upstreamErrorEnvelope({
|
|
67396
|
+
panelId: panel.id,
|
|
67397
|
+
kind,
|
|
67398
|
+
error: error52,
|
|
67399
|
+
link: panel.link ?? panel.url,
|
|
67400
|
+
upstreamDate: response?.headers.get("date")
|
|
67401
|
+
})
|
|
67402
|
+
);
|
|
67068
67403
|
}
|
|
67069
67404
|
|
|
67070
67405
|
// packages/server/src/allowlist.ts
|
|
@@ -67074,17 +67409,26 @@ function deriveAllowlist(config2) {
|
|
|
67074
67409
|
for (const panel of board.panels) {
|
|
67075
67410
|
const source = panel.source ? config2.sources[panel.source] : void 0;
|
|
67076
67411
|
const calls = callsFor(panel, source);
|
|
67077
|
-
if (calls) allowed.set(`${boardName}/${panel.id}`,
|
|
67412
|
+
if (calls) allowed.set(`${boardName}/${panel.id}`, /* @__PURE__ */ new Set(["read"]));
|
|
67413
|
+
if (panel.type === "pull-request-health" && source?.type === "github-actions") {
|
|
67414
|
+
allowed.set(
|
|
67415
|
+
`${boardName}/${panel.id}`,
|
|
67416
|
+
/* @__PURE__ */ new Set(["pull-requests", "update-workflow", "pull-request-build"])
|
|
67417
|
+
);
|
|
67418
|
+
}
|
|
67078
67419
|
}
|
|
67079
67420
|
}
|
|
67080
67421
|
return allowed;
|
|
67081
67422
|
}
|
|
67423
|
+
function permitsPanelOperation(allowlist, board, panel, operation2) {
|
|
67424
|
+
return allowlist.get(`${board}/${panel}`)?.has(operation2) ?? false;
|
|
67425
|
+
}
|
|
67082
67426
|
function callsFor(panel, source) {
|
|
67083
67427
|
if (panel.type === "pipeline-status" && source?.type === "github-actions") {
|
|
67084
67428
|
return permittedGithubActionsCalls(panel, source);
|
|
67085
67429
|
}
|
|
67086
|
-
if (panel.type === "
|
|
67087
|
-
return
|
|
67430
|
+
if (panel.type === "pipeline-status" && source?.type === "azure-devops") {
|
|
67431
|
+
return permittedAzureDevOpsCalls(panel, source);
|
|
67088
67432
|
}
|
|
67089
67433
|
if (panel.type === "http-value") return permittedHttpValueCalls(panel);
|
|
67090
67434
|
return void 0;
|
|
@@ -67169,7 +67513,6 @@ function serializeForScriptTag(value) {
|
|
|
67169
67513
|
function createApp(deps) {
|
|
67170
67514
|
const { config: config2 } = deps;
|
|
67171
67515
|
const templates = new TemplateCache(deps.fetcher ?? globalThis.fetch);
|
|
67172
|
-
const clientVersion = deps.clientVersion ?? deriveVersionLabel(config2.assetPath);
|
|
67173
67516
|
const selectedBoard = config2.board ?? Object.keys(deps.boardConfig?.boards ?? {})[0] ?? "ze-great-team";
|
|
67174
67517
|
const allowlist = deps.boardConfig ? deriveAllowlist(deps.boardConfig) : /* @__PURE__ */ new Map();
|
|
67175
67518
|
const credentials = deps.credentials ?? environmentCredentials();
|
|
@@ -67178,7 +67521,7 @@ function createApp(deps) {
|
|
|
67178
67521
|
app.get("/health", (c5) => c5.json({ status: "ok" }));
|
|
67179
67522
|
app.use("/api/*", async (_c5, next) => next());
|
|
67180
67523
|
app.get(`${config2.proxyPath}/client`, (c5) => {
|
|
67181
|
-
const identity = { assetPath: config2.assetPath
|
|
67524
|
+
const identity = { assetPath: config2.assetPath };
|
|
67182
67525
|
return c5.json(identity, 200, { "cache-control": "no-store" });
|
|
67183
67526
|
});
|
|
67184
67527
|
app.get("/", (c5) => renderEntrypoint(c5.req.raw, selectedBoard));
|
|
@@ -67236,7 +67579,7 @@ ${(0, import_yaml.stringify)(outputConfig, { sortMapEntries: true })}`,
|
|
|
67236
67579
|
const board = deps.boardConfig?.boards[boardName];
|
|
67237
67580
|
const panel = board?.panels.find((candidate) => candidate.id === panelId);
|
|
67238
67581
|
const source = panel?.source ? deps.boardConfig?.sources[panel.source] : void 0;
|
|
67239
|
-
if (!panel || panel.type !== "http-value" && !source || !allowlist
|
|
67582
|
+
if (!panel || panel.type !== "http-value" && !source || !permitsPanelOperation(allowlist, boardName, panelId, "read"))
|
|
67240
67583
|
return c5.notFound();
|
|
67241
67584
|
if (panel.type === "pipeline-status" && source?.type === "github-actions" && source) {
|
|
67242
67585
|
const result = await fetchGithubActionsPipeline({
|
|
@@ -67246,46 +67589,93 @@ ${(0, import_yaml.stringify)(outputConfig, { sortMapEntries: true })}`,
|
|
|
67246
67589
|
fetcher: deps.fetcher ?? globalThis.fetch,
|
|
67247
67590
|
githubClient
|
|
67248
67591
|
});
|
|
67249
|
-
|
|
67250
|
-
|
|
67251
|
-
|
|
67252
|
-
|
|
67253
|
-
return new Response(JSON.stringify(envelope), { status: 200, headers });
|
|
67254
|
-
}
|
|
67255
|
-
if (panel.type === "pull-request-health" && source?.type === "github-actions" && source) {
|
|
67256
|
-
const result = await fetchGithubActionsPullRequestHealth({
|
|
67592
|
+
return adapterRouteResponse(result);
|
|
67593
|
+
}
|
|
67594
|
+
if (panel.type === "pipeline-status" && source?.type === "azure-devops" && source) {
|
|
67595
|
+
const result = await fetchAzureDevOpsPipeline({
|
|
67257
67596
|
panel,
|
|
67258
67597
|
source,
|
|
67259
67598
|
requestHeaders: c5.req.raw.headers,
|
|
67260
67599
|
fetcher: deps.fetcher ?? globalThis.fetch,
|
|
67261
|
-
|
|
67600
|
+
credentials
|
|
67262
67601
|
});
|
|
67263
|
-
|
|
67264
|
-
const envelope = result.envelope ?? JSON.parse(await result.response.text());
|
|
67265
|
-
headers.set("content-type", "application/json; charset=utf-8");
|
|
67266
|
-
return new Response(JSON.stringify(envelope), { status: 200, headers });
|
|
67602
|
+
return adapterRouteResponse(result);
|
|
67267
67603
|
}
|
|
67604
|
+
if (panel.type === "pull-request-health") return c5.notFound();
|
|
67268
67605
|
if (panel.type === "http-value") {
|
|
67269
67606
|
const result = await fetchHttpValue({
|
|
67270
67607
|
panel,
|
|
67271
67608
|
requestHeaders: c5.req.raw.headers,
|
|
67272
67609
|
fetcher: deps.fetcher ?? globalThis.fetch
|
|
67273
67610
|
});
|
|
67274
|
-
|
|
67275
|
-
if (result.response.status === 304) return new Response(null, { status: 304, headers });
|
|
67276
|
-
const envelope = result.envelope ?? JSON.parse(await result.response.text());
|
|
67277
|
-
headers.set("content-type", "application/json; charset=utf-8");
|
|
67278
|
-
return new Response(JSON.stringify(envelope), { status: 200, headers });
|
|
67611
|
+
return adapterRouteResponse(result);
|
|
67279
67612
|
}
|
|
67280
67613
|
return c5.notFound();
|
|
67281
67614
|
});
|
|
67615
|
+
app.get("/api/panel/:board/:panelId/pull-requests", async (c5) => {
|
|
67616
|
+
const resolved = pullRequestPanel(c5.req.param("board"), c5.req.param("panelId"), "pull-requests");
|
|
67617
|
+
if (!resolved) return c5.notFound();
|
|
67618
|
+
return adapterRouteResponse(
|
|
67619
|
+
await fetchGithubActionsPullRequestCandidates({
|
|
67620
|
+
...resolved,
|
|
67621
|
+
requestHeaders: c5.req.raw.headers,
|
|
67622
|
+
fetcher: deps.fetcher ?? globalThis.fetch,
|
|
67623
|
+
githubClient
|
|
67624
|
+
})
|
|
67625
|
+
);
|
|
67626
|
+
});
|
|
67627
|
+
app.get("/api/panel/:board/:panelId/update-workflow/:workflow", async (c5) => {
|
|
67628
|
+
const resolved = pullRequestPanel(
|
|
67629
|
+
c5.req.param("board"),
|
|
67630
|
+
c5.req.param("panelId"),
|
|
67631
|
+
"update-workflow"
|
|
67632
|
+
);
|
|
67633
|
+
const workflow = c5.req.param("workflow");
|
|
67634
|
+
if (!resolved?.capabilities.configuredUpdateWorkflow(workflow)) return c5.notFound();
|
|
67635
|
+
return adapterRouteResponse(
|
|
67636
|
+
await fetchGithubActionsUpdateWorkflow({
|
|
67637
|
+
...resolved,
|
|
67638
|
+
workflow,
|
|
67639
|
+
requestHeaders: c5.req.raw.headers,
|
|
67640
|
+
fetcher: deps.fetcher ?? globalThis.fetch,
|
|
67641
|
+
githubClient
|
|
67642
|
+
})
|
|
67643
|
+
);
|
|
67644
|
+
});
|
|
67645
|
+
app.get("/api/panel/:board/:panelId/pull-request-build", async (c5) => {
|
|
67646
|
+
const resolved = pullRequestPanel(
|
|
67647
|
+
c5.req.param("board"),
|
|
67648
|
+
c5.req.param("panelId"),
|
|
67649
|
+
"pull-request-build"
|
|
67650
|
+
);
|
|
67651
|
+
const branch = c5.req.query("branch");
|
|
67652
|
+
if (!resolved || !branch || !resolved.capabilities.permitsBuildBranch(branch))
|
|
67653
|
+
return c5.notFound();
|
|
67654
|
+
return adapterRouteResponse(
|
|
67655
|
+
await fetchGithubActionsPullRequestBuild({
|
|
67656
|
+
...resolved,
|
|
67657
|
+
branch,
|
|
67658
|
+
requestHeaders: c5.req.raw.headers,
|
|
67659
|
+
fetcher: deps.fetcher ?? globalThis.fetch,
|
|
67660
|
+
githubClient
|
|
67661
|
+
})
|
|
67662
|
+
);
|
|
67663
|
+
});
|
|
67664
|
+
function pullRequestPanel(boardName, panelId, operation2) {
|
|
67665
|
+
const panel = deps.boardConfig?.boards[boardName]?.panels.find(
|
|
67666
|
+
(candidate) => candidate.id === panelId
|
|
67667
|
+
);
|
|
67668
|
+
const source = panel?.source ? deps.boardConfig?.sources[panel.source] : void 0;
|
|
67669
|
+
const capabilities = panel?.type === "pull-request-health" ? pullRequestHealthCapabilities(panel) : void 0;
|
|
67670
|
+
if (!capabilities) return void 0;
|
|
67671
|
+
return panel?.type === "pull-request-health" && source?.type === "github-actions" && permitsPanelOperation(allowlist, boardName, panelId, operation2) ? { panel, source, capabilities } : void 0;
|
|
67672
|
+
}
|
|
67282
67673
|
async function renderEntrypoint(_request, board) {
|
|
67283
67674
|
const template = await templates.get(config2.assetPath);
|
|
67284
67675
|
const env2 = {
|
|
67285
67676
|
assetPath: config2.assetPath,
|
|
67286
67677
|
proxyPath: config2.proxyPath,
|
|
67287
|
-
board
|
|
67288
|
-
clientVersion
|
|
67678
|
+
board
|
|
67289
67679
|
};
|
|
67290
67680
|
return new Response(renderIndexHtml(template, env2), {
|
|
67291
67681
|
headers: {
|
|
@@ -67302,20 +67692,6 @@ function safeDownloadFilename(value) {
|
|
|
67302
67692
|
const sanitized = value.replace(/[\\/\r\n"%*:|<>?]/g, "_").trim();
|
|
67303
67693
|
return sanitized || "board";
|
|
67304
67694
|
}
|
|
67305
|
-
function passthroughHeaders(upstream) {
|
|
67306
|
-
const headers = new Headers();
|
|
67307
|
-
for (const name of ["cache-control", "etag", "last-modified", "date", "vary"]) {
|
|
67308
|
-
const value = upstream.get(name);
|
|
67309
|
-
if (value) headers.set(name, value);
|
|
67310
|
-
}
|
|
67311
|
-
return headers;
|
|
67312
|
-
}
|
|
67313
|
-
function deriveVersionLabel(assetPath) {
|
|
67314
|
-
const segments = assetPath.split("/").filter((segment) => segment !== "");
|
|
67315
|
-
const last = segments.at(-1);
|
|
67316
|
-
if (last === void 0) return "unknown";
|
|
67317
|
-
return last === ASSET_PATH_SENTINEL.replace("/", "") ? "dev" : last;
|
|
67318
|
-
}
|
|
67319
67695
|
|
|
67320
67696
|
// packages/server/src/board-config.ts
|
|
67321
67697
|
import { readFile as readFile3 } from "node:fs/promises";
|