@prisma/composer-prisma-cloud 0.6.0-dev.20 → 0.6.0-dev.22
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/dist/auth/pack.mjs +1 -1
- package/dist/auth/pack.mjs.map +1 -1
- package/dist/auth/testing.mjs +1 -1
- package/dist/auth/testing.mjs.map +1 -1
- package/dist/control.d.mts +1 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +420 -2
- package/dist/control.mjs.map +1 -1
- package/dist/local-target.mjs +1 -1
- package/dist/{s3-credentials-resource-BltGd-gG-B_bNhtGi.mjs → s3-credentials-resource-BltGd-gG-2K8Cgwoi.mjs} +6 -4
- package/dist/s3-credentials-resource-BltGd-gG-2K8Cgwoi.mjs.map +1 -0
- package/package.json +19 -19
- package/dist/s3-credentials-resource-BltGd-gG-B_bNhtGi.mjs.map +0 -1
package/dist/control.d.mts
CHANGED
|
@@ -10,7 +10,7 @@ import { Resource } from "alchemy";
|
|
|
10
10
|
import "effect/Schedule";
|
|
11
11
|
import * as Output from "alchemy/Output";
|
|
12
12
|
import { ExtensionDescriptor, StateDescriptor } from "@prisma/composer/config";
|
|
13
|
-
//#region ../../1-prisma-cloud/0-lowering/lowering/dist/compute-
|
|
13
|
+
//#region ../../1-prisma-cloud/0-lowering/lowering/dist/compute-CW3HkgJe.d.mts
|
|
14
14
|
/** Every region Prisma Compute serves — the runtime source of truth; `ComputeRegion` is derived from it so the two can never drift. */
|
|
15
15
|
declare const COMPUTE_REGIONS: readonly ["us-east-1", "us-west-1", "eu-west-3", "eu-central-1", "ap-northeast-1", "ap-southeast-1"];
|
|
16
16
|
type ComputeRegion = (typeof COMPUTE_REGIONS)[number];
|
package/dist/control.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control.d.mts","names":[],"sources":["../../../1-prisma-cloud/0-lowering/lowering/dist/compute-
|
|
1
|
+
{"version":3,"file":"control.d.mts","names":[],"sources":["../../../1-prisma-cloud/0-lowering/lowering/dist/compute-CW3HkgJe.d.mts","../../../1-prisma-cloud/1-extensions/target/dist/control.d.mts"],"mappings":";;;;;;;;;;;;;;cA4Dc;KACT,wBAAwB;;;;;;;;;;;;;;;;;;;UCzCnB,sBAAsB;;;;;;;;WAQrB,QAAQ,6BAA6B,OAAO;;;;;;;;UAQ7C;WACC,gBAAgB,OAAO;;;;;;;;;;;;UAYxB,6BAA6B;WAC5B,kBAAkB,aAAa,8BAA8B,oBAAoB,OAAO;;;;;cAKrF,mBAAmB;UACvB;;EAER;;EAEA,SAAS;;;;;;;;KAQN,qBAAqB,KAAK,0BAA0B,KAAK;;;;;;;;;;iBAU7C,oBAAoB,kBAAkB,sBAAsB,QAAQ,oBAAoB,sBAAsB,oBAAoB,gBAAgB;cACrJ,iBAAiB,oBAAoB,gBAAgB;;cAErD,cAAc,OAAO,uBAAuB"}
|
package/dist/control.mjs
CHANGED
|
@@ -2,11 +2,12 @@ import { o as paramBindingFor, s as paramName } from "./secret-Doubjztg-CWHCDiuX
|
|
|
2
2
|
import { a as encodeParamPointer, i as encode, l as serializeInput, n as configKey, o as paramEntries } from "./serializer-Ch1Tmx-2-D7cNhkEp.mjs";
|
|
3
3
|
import { a as provisionedEdges, n as SELF_ORIGIN, r as STREAMS_API_KEY, t as RESERVED_PROVIDER_PARAMS } from "./provisioned-edges-COr17uxy-DymAGn_V.mjs";
|
|
4
4
|
import { n as requiredPackHeadOf } from "./required-pack-head-BrrJarzc-DeP50pBu.mjs";
|
|
5
|
-
import { A as packageComputeArtifact, B as
|
|
5
|
+
import { A as packageComputeArtifact, B as PrismaCredentials, D as EnvironmentVariable, E as Deployment, F as resolveDefaultBranchId, H as layer, I as PrismaApiError, L as call, M as BucketKey, N as collectPages, O as ServiceKey, P as drivePagesAsync, R as MANAGEMENT_API_ORIGIN, S as Database, T as ComputeService, V as fromEnv, _ as resolveTargetRef, a as PgWarmProvider, b as providers, d as collectPreflightNames, f as containerDescriptor, g as resolvePrismaNextConfig, h as prismaCloudContainerOf, i as PgWarm, j as Bucket, k as ServiceKeyProvider, l as S3Credentials, m as packHeadRefHashes, n as GeneratedParamProvider, o as PnMigration, r as PRISMA_CLOUD_EXTENSION_ID, s as PnMigrationProvider, t as GeneratedParam, u as S3CredentialsProvider, w as COMPUTE_REGIONS, x as Connection, z as ManagementClient } from "./s3-credentials-resource-BltGd-gG-2K8Cgwoi.mjs";
|
|
6
6
|
import { n as isPnPostgresResourceNode } from "./prisma-next-hB3CQxKI-BYVc-k-F.mjs";
|
|
7
7
|
import { isParamSource } from "@prisma/composer";
|
|
8
8
|
import { blindCast } from "@prisma/composer/casts";
|
|
9
9
|
import { RPC_PEER_KEY } from "@prisma/composer/service-rpc";
|
|
10
|
+
import { createManagementApiClient } from "@prisma/management-api-sdk";
|
|
10
11
|
import * as Effect from "effect/Effect";
|
|
11
12
|
import * as Layer from "effect/Layer";
|
|
12
13
|
import * as Redacted from "effect/Redacted";
|
|
@@ -18,8 +19,208 @@ import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient";
|
|
|
18
19
|
import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
|
|
19
20
|
import * as Headers from "effect/unstable/http/Headers";
|
|
20
21
|
import * as Output from "alchemy/Output";
|
|
22
|
+
import { execFileSync } from "node:child_process";
|
|
23
|
+
//#region ../../1-prisma-cloud/0-lowering/lowering/dist/resources-rlwsFefZ.mjs
|
|
24
|
+
/**
|
|
25
|
+
* Reporting is observability, so no call may stall the deploy: every request
|
|
26
|
+
* carries this deadline, and an expired one is warned and dropped like any
|
|
27
|
+
* other failure.
|
|
28
|
+
*/
|
|
29
|
+
const REPORT_DEADLINE_MS = 1e4;
|
|
30
|
+
function buildsApi(options) {
|
|
31
|
+
const { client, warn } = options;
|
|
32
|
+
/** Runs one call, turning every failure — transport or refusal — into a warning and `undefined`. */
|
|
33
|
+
const send = async (call, describe) => {
|
|
34
|
+
let result;
|
|
35
|
+
try {
|
|
36
|
+
result = await call();
|
|
37
|
+
} catch (error) {
|
|
38
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
39
|
+
warn(`Could not reach Prisma Cloud to ${describe}: ${detail}`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (!result.response.ok) {
|
|
43
|
+
const detail = result.error === void 0 ? "" : `: ${JSON.stringify(result.error)}`;
|
|
44
|
+
warn(`Prisma Cloud refused to ${describe} (HTTP ${String(result.response.status)})${detail}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
return result.data ?? {};
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
async create(body) {
|
|
51
|
+
const created = await send(() => client.POST("/v1/builds", {
|
|
52
|
+
body,
|
|
53
|
+
signal: AbortSignal.timeout(REPORT_DEADLINE_MS)
|
|
54
|
+
}), "record this deploy");
|
|
55
|
+
if (created === void 0) return void 0;
|
|
56
|
+
const id = created.data?.id;
|
|
57
|
+
if (id === void 0 || id.length === 0) {
|
|
58
|
+
warn("Prisma Cloud recorded this deploy but returned no build id.");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
return id;
|
|
62
|
+
},
|
|
63
|
+
async update(id, body) {
|
|
64
|
+
return await send(() => client.PATCH("/v1/builds/{buildId}", {
|
|
65
|
+
params: { path: { buildId: id } },
|
|
66
|
+
body,
|
|
67
|
+
signal: AbortSignal.timeout(REPORT_DEADLINE_MS)
|
|
68
|
+
}), "update this deploy's build") !== void 0;
|
|
69
|
+
},
|
|
70
|
+
async reportResource(id, resourceType, resourceId, action) {
|
|
71
|
+
return await send(() => client.PUT("/v1/builds/{buildId}/resources/{resourceType}/{resourceId}", {
|
|
72
|
+
params: { path: {
|
|
73
|
+
buildId: id,
|
|
74
|
+
resourceType,
|
|
75
|
+
resourceId
|
|
76
|
+
} },
|
|
77
|
+
body: { action },
|
|
78
|
+
signal: AbortSignal.timeout(REPORT_DEADLINE_MS)
|
|
79
|
+
}), `record the ${resourceType} this deploy ${action === "acted_on" ? "acted on" : action}`) !== void 0;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** Names the build a run belongs to. Set by the CLI on the alchemy child, or by a CI runner that created the build itself. */
|
|
84
|
+
const BUILD_ID_ENV = "PRISMA_BUILD_ID";
|
|
85
|
+
/**
|
|
86
|
+
* Alchemy resource type → platform resource type.
|
|
87
|
+
*
|
|
88
|
+
* Two of this package's resources are deliberately absent. `Prisma.BucketKey`
|
|
89
|
+
* has no platform resource type to map onto. `PrismaCloud.ServiceKey` is a
|
|
90
|
+
* value this deploy mints locally, not a platform resource at all — the
|
|
91
|
+
* platform's `service_key` is what `Prisma.Connection` creates.
|
|
92
|
+
*
|
|
93
|
+
* Anything not listed — `PgWarm`, and every resource another extension
|
|
94
|
+
* contributes — is not a Prisma Cloud resource and is not reported.
|
|
95
|
+
*/
|
|
96
|
+
const PLATFORM_RESOURCES = {
|
|
97
|
+
"Prisma.Project": {
|
|
98
|
+
type: "project",
|
|
99
|
+
idField: "id"
|
|
100
|
+
},
|
|
101
|
+
"Prisma.Database": {
|
|
102
|
+
type: "database",
|
|
103
|
+
idField: "id"
|
|
104
|
+
},
|
|
105
|
+
"Prisma.Connection": {
|
|
106
|
+
type: "service_key",
|
|
107
|
+
idField: "id"
|
|
108
|
+
},
|
|
109
|
+
"Prisma.Bucket": {
|
|
110
|
+
type: "bucket",
|
|
111
|
+
idField: "id"
|
|
112
|
+
},
|
|
113
|
+
"Prisma.ComputeService": {
|
|
114
|
+
type: "app",
|
|
115
|
+
idField: "id"
|
|
116
|
+
},
|
|
117
|
+
"Prisma.Deployment": {
|
|
118
|
+
type: "deployment",
|
|
119
|
+
idField: "deploymentId"
|
|
120
|
+
},
|
|
121
|
+
"Prisma.EnvironmentVariable": {
|
|
122
|
+
type: "config_variable",
|
|
123
|
+
idField: "id"
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Terminal status → what the run did to the resource. The intermediate
|
|
128
|
+
* statuses (`creating`, `updating`, `replacing`) are skipped: they say work
|
|
129
|
+
* started, not that it landed, and the terminal write follows immediately.
|
|
130
|
+
*
|
|
131
|
+
* `updated` maps to `acted_on` rather than to nothing, because a reconcile
|
|
132
|
+
* that changed no field is still this run acting on that resource — a
|
|
133
|
+
* migration against an untouched database is an action on it.
|
|
134
|
+
*/
|
|
135
|
+
const ACTION_BY_STATUS = {
|
|
136
|
+
created: "created",
|
|
137
|
+
updated: "acted_on",
|
|
138
|
+
deleting: "deleted"
|
|
139
|
+
};
|
|
140
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
141
|
+
/**
|
|
142
|
+
* What a persisted state record says this run did, or `undefined` when it
|
|
143
|
+
* says nothing reportable. Reads defensively: the record crosses a wire and
|
|
144
|
+
* carries resources from every extension, not only this one's.
|
|
145
|
+
*/
|
|
146
|
+
function reportableResource(value) {
|
|
147
|
+
if (!isRecord(value)) return void 0;
|
|
148
|
+
if (value["kind"] === "action") return void 0;
|
|
149
|
+
if (value["adopting"] === true) return void 0;
|
|
150
|
+
const resourceType = value["resourceType"];
|
|
151
|
+
if (typeof resourceType !== "string") return void 0;
|
|
152
|
+
const mapping = PLATFORM_RESOURCES[resourceType];
|
|
153
|
+
if (mapping === void 0) return void 0;
|
|
154
|
+
const status = value["status"];
|
|
155
|
+
const action = typeof status === "string" ? ACTION_BY_STATUS[status] : void 0;
|
|
156
|
+
if (action === void 0) return void 0;
|
|
157
|
+
const attr = value["attr"];
|
|
158
|
+
if (!isRecord(attr)) return void 0;
|
|
159
|
+
const id = attr[mapping.idField];
|
|
160
|
+
if (typeof id !== "string" || id.length === 0) return void 0;
|
|
161
|
+
return {
|
|
162
|
+
type: mapping.type,
|
|
163
|
+
id,
|
|
164
|
+
action
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The most a drain will wait, total. Every real report already carries the
|
|
169
|
+
* api layer's per-request deadline, so this never fires for the shipped
|
|
170
|
+
* `BuildsApi`; it is the backstop that keeps the state layer's finalizer —
|
|
171
|
+
* and therefore the deploy lease release — bounded against any implementation.
|
|
172
|
+
*/
|
|
173
|
+
const DRAIN_DEADLINE_MS = 15e3;
|
|
174
|
+
function resourceReporter(api, buildId, warn = (message) => console.warn(message), drainDeadlineMs = DRAIN_DEADLINE_MS) {
|
|
175
|
+
const inFlight = /* @__PURE__ */ new Set();
|
|
176
|
+
const reported = /* @__PURE__ */ new Set();
|
|
177
|
+
return {
|
|
178
|
+
observe(value) {
|
|
179
|
+
const resource = reportableResource(value);
|
|
180
|
+
if (resource === void 0) return;
|
|
181
|
+
const key = `${resource.type}:${resource.id}:${resource.action}`;
|
|
182
|
+
if (reported.has(key)) return;
|
|
183
|
+
reported.add(key);
|
|
184
|
+
const sent = api.reportResource(buildId, resource.type, resource.id, resource.action).finally(() => inFlight.delete(sent));
|
|
185
|
+
inFlight.add(sent);
|
|
186
|
+
},
|
|
187
|
+
async drain() {
|
|
188
|
+
const deadline = Date.now() + drainDeadlineMs;
|
|
189
|
+
while (inFlight.size > 0) {
|
|
190
|
+
const remaining = deadline - Date.now();
|
|
191
|
+
if (remaining <= 0) {
|
|
192
|
+
warn(`Abandoned ${inFlight.size} in-flight resource report(s) after ${drainDeadlineMs}ms.`);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
await Promise.race([Promise.allSettled([...inFlight]), new Promise((resolve) => setTimeout(resolve, remaining).unref?.())]);
|
|
196
|
+
if (Date.now() >= deadline && inFlight.size > 0) {
|
|
197
|
+
warn(`Abandoned ${inFlight.size} in-flight resource report(s) after ${drainDeadlineMs}ms.`);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
//#endregion
|
|
21
205
|
//#region ../../1-prisma-cloud/0-lowering/lowering/dist/state.mjs
|
|
22
206
|
/**
|
|
207
|
+
* Reports on the way out of a successful `set`, never before it: a write that
|
|
208
|
+
* failed leaves the resource unrecorded here, and claiming otherwise would
|
|
209
|
+
* make the build's provenance a guess.
|
|
210
|
+
*/
|
|
211
|
+
function withResourceReporting(inner, api, buildId, warn) {
|
|
212
|
+
const reporter = resourceReporter(api, buildId, warn);
|
|
213
|
+
return {
|
|
214
|
+
store: {
|
|
215
|
+
...inner,
|
|
216
|
+
set(request) {
|
|
217
|
+
return inner.set(request).pipe(Effect.tap(() => Effect.sync(() => reporter.observe(request.value))));
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
reporter
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
23
224
|
* Whether the platform state API holds any resources for (stack, stage).
|
|
24
225
|
* Requires the live deploy lease — the listing runs under it, like every
|
|
25
226
|
* state operation.
|
|
@@ -250,10 +451,217 @@ const stateLayerAgainst = (apiOrigin, ids) => {
|
|
|
250
451
|
transformClient: (req) => HttpClientRequest.setHeader(req, LEASE_HEADER, Redacted.value(lease.leaseId)),
|
|
251
452
|
id: "prisma-postgres"
|
|
252
453
|
}).pipe(Effect.provide(FetchHttpClient.layer));
|
|
253
|
-
|
|
454
|
+
const buildId = process.env[BUILD_ID_ENV];
|
|
455
|
+
if (buildId === void 0 || buildId.length === 0) return Effect.succeed(service);
|
|
456
|
+
const { store, reporter } = withResourceReporting(service, buildsApi({
|
|
457
|
+
client: mgmt,
|
|
458
|
+
warn: (message) => {
|
|
459
|
+
console.warn(message);
|
|
460
|
+
}
|
|
461
|
+
}), buildId);
|
|
462
|
+
yield* Effect.addFinalizer(() => Effect.promise(() => reporter.drain()));
|
|
463
|
+
return Effect.succeed(store);
|
|
254
464
|
}).pipe(Effect.provide(dependencies))).pipe(Layer.orDie, Layer.merge(redactLeaseHeader));
|
|
255
465
|
};
|
|
256
466
|
//#endregion
|
|
467
|
+
//#region ../../1-prisma-cloud/0-lowering/lowering/dist/builds.mjs
|
|
468
|
+
/**
|
|
469
|
+
* Who is deploying, and from what commit — the identity a build is reported
|
|
470
|
+
* under.
|
|
471
|
+
*
|
|
472
|
+
* `commitSha` and `branchName` are required by the platform, and Composer has
|
|
473
|
+
* no other reason to read git, so this is the only place it does. A deploy
|
|
474
|
+
* from a directory that is not a git checkout has neither, and is reported
|
|
475
|
+
* not at all rather than reported with placeholder values: the Console keeps
|
|
476
|
+
* whatever it is told, and "unknown" would sit in a workspace's deploy
|
|
477
|
+
* history permanently.
|
|
478
|
+
*/
|
|
479
|
+
const DIGITS = /^[0-9]+$/;
|
|
480
|
+
const nonEmpty$1 = (value) => value !== void 0 && value.length > 0 ? value : void 0;
|
|
481
|
+
function git(args, cwd) {
|
|
482
|
+
try {
|
|
483
|
+
const out = execFileSync("git", [...args], {
|
|
484
|
+
cwd,
|
|
485
|
+
encoding: "utf8",
|
|
486
|
+
stdio: [
|
|
487
|
+
"ignore",
|
|
488
|
+
"pipe",
|
|
489
|
+
"ignore"
|
|
490
|
+
],
|
|
491
|
+
timeout: 5e3
|
|
492
|
+
});
|
|
493
|
+
return nonEmpty$1(out.trim());
|
|
494
|
+
} catch {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* The GitHub Actions run this is executing inside, when all three parts are
|
|
500
|
+
* present and are the digits the platform's dedup key requires. Partial or
|
|
501
|
+
* malformed input yields nothing rather than half an identity: the key joins
|
|
502
|
+
* its parts with `:`, so a part that is not digits could let two different
|
|
503
|
+
* runs spell the same key.
|
|
504
|
+
*/
|
|
505
|
+
function githubRunIdentity(env) {
|
|
506
|
+
if (env["GITHUB_ACTIONS"] !== "true") return void 0;
|
|
507
|
+
const repositoryId = nonEmpty$1(env["GITHUB_REPOSITORY_ID"]);
|
|
508
|
+
const runId = nonEmpty$1(env["GITHUB_RUN_ID"]);
|
|
509
|
+
const attempt = nonEmpty$1(env["GITHUB_RUN_ATTEMPT"]) ?? "1";
|
|
510
|
+
if (repositoryId === void 0 || !DIGITS.test(repositoryId)) return void 0;
|
|
511
|
+
if (runId === void 0 || !DIGITS.test(runId)) return void 0;
|
|
512
|
+
if (!DIGITS.test(attempt)) return void 0;
|
|
513
|
+
const runAttempt = Number.parseInt(attempt, 10);
|
|
514
|
+
if (!Number.isInteger(runAttempt) || runAttempt < 1) return void 0;
|
|
515
|
+
return {
|
|
516
|
+
provider: "github",
|
|
517
|
+
repositoryId,
|
|
518
|
+
runId,
|
|
519
|
+
runAttempt
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
function githubRunUrl(env) {
|
|
523
|
+
const server = nonEmpty$1(env["GITHUB_SERVER_URL"]) ?? "https://github.com";
|
|
524
|
+
const repository = nonEmpty$1(env["GITHUB_REPOSITORY"]);
|
|
525
|
+
const runId = nonEmpty$1(env["GITHUB_RUN_ID"]);
|
|
526
|
+
if (repository === void 0 || runId === void 0) return void 0;
|
|
527
|
+
return `${server}/${repository}/actions/runs/${runId}/attempts/${nonEmpty$1(env["GITHUB_RUN_ATTEMPT"]) ?? "1"}`;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* The branch this ran on. Inside a pull-request workflow `GITHUB_REF_NAME` is
|
|
531
|
+
* the synthetic merge ref (`123/merge`), so the head branch is preferred —
|
|
532
|
+
* it is the name a person would recognise in the Console.
|
|
533
|
+
*/
|
|
534
|
+
function branchName(env, cwd) {
|
|
535
|
+
const fromEnv = nonEmpty$1(env["GITHUB_HEAD_REF"]) ?? nonEmpty$1(env["GITHUB_REF_NAME"]);
|
|
536
|
+
if (fromEnv !== void 0) return fromEnv;
|
|
537
|
+
const head = git([
|
|
538
|
+
"rev-parse",
|
|
539
|
+
"--abbrev-ref",
|
|
540
|
+
"HEAD"
|
|
541
|
+
], cwd);
|
|
542
|
+
return head === "HEAD" ? void 0 : head;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* The identity to report this run under, or `undefined` when there is not
|
|
546
|
+
* enough to report one honestly.
|
|
547
|
+
*/
|
|
548
|
+
function resolveRunIdentity(cwd, env) {
|
|
549
|
+
const commitSha = nonEmpty$1(env["GITHUB_SHA"]) ?? git(["rev-parse", "HEAD"], cwd);
|
|
550
|
+
const branch = branchName(env, cwd);
|
|
551
|
+
if (commitSha === void 0 || branch === void 0) return void 0;
|
|
552
|
+
const runIdentity = githubRunIdentity(env);
|
|
553
|
+
return {
|
|
554
|
+
source: runIdentity === void 0 ? "cli" : "ci",
|
|
555
|
+
commitSha,
|
|
556
|
+
branchName: branch,
|
|
557
|
+
runIdentity,
|
|
558
|
+
externalLogUrl: runIdentity === void 0 ? void 0 : githubRunUrl(env)
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
/** An empty string is how a shell spells "unset", so it must not be mistaken for a build id. */
|
|
562
|
+
const nonEmpty = (value) => value !== void 0 && value.length > 0 ? value : void 0;
|
|
563
|
+
function buildReporter(options) {
|
|
564
|
+
return { begin: async (input) => {
|
|
565
|
+
try {
|
|
566
|
+
return await beginSession(input, options);
|
|
567
|
+
} catch (error) {
|
|
568
|
+
(options.warn ?? ((message) => console.warn(message)))(`Could not start build reporting: ${error instanceof Error ? error.message : String(error)}`);
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
} };
|
|
572
|
+
}
|
|
573
|
+
async function beginSession(input, options) {
|
|
574
|
+
const env = options.env ?? process.env;
|
|
575
|
+
const warn = options.warn ?? ((message) => console.warn(message));
|
|
576
|
+
const injected = input.credentials?.client;
|
|
577
|
+
const token = env["PRISMA_SERVICE_TOKEN"];
|
|
578
|
+
if (options.api === void 0 && injected === void 0 && (token === void 0 || token.length === 0)) return;
|
|
579
|
+
const identity = resolveRunIdentity(input.cwd, env);
|
|
580
|
+
if (identity === void 0) {
|
|
581
|
+
warn(`\nNot recording this deploy in Prisma Cloud: ${input.cwd} has no commit and branch to report it under. Deploy from a git checkout to see it in the Console.`);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
const api = options.api ?? buildsApi({
|
|
585
|
+
client: injected ?? createManagementApiClient({
|
|
586
|
+
token: token ?? "",
|
|
587
|
+
baseUrl: options.origin ?? "https://api.prisma.io"
|
|
588
|
+
}),
|
|
589
|
+
warn
|
|
590
|
+
});
|
|
591
|
+
const joined = nonEmpty(input.reportId) ?? nonEmpty(env["PRISMA_BUILD_ID"]);
|
|
592
|
+
const buildId = joined !== void 0 ? joined : await api.create({
|
|
593
|
+
source: identity.source,
|
|
594
|
+
commitSha: identity.commitSha,
|
|
595
|
+
branchName: identity.branchName,
|
|
596
|
+
...identity.runIdentity !== void 0 ? { runIdentity: identity.runIdentity } : {},
|
|
597
|
+
...identity.externalLogUrl !== void 0 ? { externalLogUrl: identity.externalLogUrl } : {}
|
|
598
|
+
});
|
|
599
|
+
if (buildId === void 0) return void 0;
|
|
600
|
+
await api.update(buildId, {
|
|
601
|
+
phase: "deploy",
|
|
602
|
+
state: "running"
|
|
603
|
+
});
|
|
604
|
+
return session(api, buildId, options.refsOf, warn);
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* The app this run deployed and where it can be reached — but only when the
|
|
608
|
+
* run deployed exactly one compute service.
|
|
609
|
+
*
|
|
610
|
+
* `Build.appId` and `Build.deployedUrl` are each one value, and an app with
|
|
611
|
+
* several services has no single answer. Picking the first would put an
|
|
612
|
+
* arbitrary service's address in the Console and quietly imply it was the
|
|
613
|
+
* app's. Single-service apps are the common case and get a working link;
|
|
614
|
+
* multi-service apps get neither, and their services are all reported through
|
|
615
|
+
* the resources endpoint regardless.
|
|
616
|
+
*
|
|
617
|
+
* Both fields are fill-only, so this is safe to send on a build whose creator
|
|
618
|
+
* already set them to the same values, and a genuine disagreement is a 409
|
|
619
|
+
* the caller logs.
|
|
620
|
+
*/
|
|
621
|
+
function deployedApp(entities) {
|
|
622
|
+
const services = entities.filter((entity) => entity.kind === "compute-service");
|
|
623
|
+
const only = services.length === 1 ? services[0] : void 0;
|
|
624
|
+
if (only === void 0) return {};
|
|
625
|
+
return {
|
|
626
|
+
appId: only.id,
|
|
627
|
+
...only.url !== void 0 ? { deployedUrl: only.url } : {}
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
function session(api, buildId, refsOf, warn) {
|
|
631
|
+
let finished = false;
|
|
632
|
+
return {
|
|
633
|
+
childEnv: () => ({ [BUILD_ID_ENV]: buildId }),
|
|
634
|
+
/**
|
|
635
|
+
* Attaches the build to the Project and Branch this deploy resolved.
|
|
636
|
+
* Sent on its own rather than folded into the progress update above:
|
|
637
|
+
* the fields are fill-only, so keeping them in their own call means a
|
|
638
|
+
* 409 from a disagreeing creator costs these references alone.
|
|
639
|
+
*/
|
|
640
|
+
async attach(input) {
|
|
641
|
+
if (input.container === void 0) return;
|
|
642
|
+
const { projectId, branchId } = refsOf(input.container);
|
|
643
|
+
await api.update(buildId, {
|
|
644
|
+
projectId,
|
|
645
|
+
...branchId !== void 0 ? { branchId } : {}
|
|
646
|
+
});
|
|
647
|
+
},
|
|
648
|
+
async finish(outcome) {
|
|
649
|
+
if (finished) return;
|
|
650
|
+
finished = true;
|
|
651
|
+
try {
|
|
652
|
+
await api.update(buildId, {
|
|
653
|
+
state: outcome.ok ? "succeeded" : outcome.cancelled ? "cancelled" : "failed",
|
|
654
|
+
...outcome.failingStep !== void 0 && !outcome.cancelled ? { failingStep: outcome.failingStep } : {},
|
|
655
|
+
...outcome.errorMessage !== void 0 && !outcome.cancelled ? { errorMessage: outcome.errorMessage } : {},
|
|
656
|
+
...deployedApp(outcome.entities)
|
|
657
|
+
});
|
|
658
|
+
} catch (error) {
|
|
659
|
+
warn(`Could not report this deploy's outcome: ${error instanceof Error ? error.message : String(error)}`);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
//#endregion
|
|
257
665
|
//#region ../../1-prisma-cloud/1-extensions/target/dist/control.mjs
|
|
258
666
|
const PRISMA_NAME_MIN = 3;
|
|
259
667
|
const PRISMA_NAME_MAX = 65;
|
|
@@ -701,6 +1109,15 @@ function s3StoreDescriptor(o) {
|
|
|
701
1109
|
})
|
|
702
1110
|
};
|
|
703
1111
|
}
|
|
1112
|
+
function prismaCloudReporter() {
|
|
1113
|
+
return buildReporter({ refsOf: (container) => {
|
|
1114
|
+
const { projectId, branchId } = prismaCloudContainerOf(container);
|
|
1115
|
+
return {
|
|
1116
|
+
projectId,
|
|
1117
|
+
branchId
|
|
1118
|
+
};
|
|
1119
|
+
} });
|
|
1120
|
+
}
|
|
704
1121
|
/** The Prisma Cloud–hosted deploy state store; its implementation lives in @internal/lowering. */
|
|
705
1122
|
/**
|
|
706
1123
|
* ADR-0031's registered provisioner for RPC_PEER_KEY: mints one `ServiceKey`
|
|
@@ -908,6 +1325,7 @@ const prismaCloud = (opts = {}) => {
|
|
|
908
1325
|
container: containerDescriptor(),
|
|
909
1326
|
providers: () => asProvidersLayer(Layer.mergeAll(providers(), PgWarmProvider(), PnMigrationProvider(), S3CredentialsProvider(), GeneratedParamProvider(), ServiceKeyProvider())),
|
|
910
1327
|
preflight: (input) => runPreflight(input),
|
|
1328
|
+
reporter: prismaCloudReporter(),
|
|
911
1329
|
application: { provision: (ctx) => Effect.gen(function* () {
|
|
912
1330
|
const { projectId, branchId } = prismaCloudContainerOf(ctx.container);
|
|
913
1331
|
for (const key of ["DATABASE_URL", "DATABASE_URL_POOLED"]) yield* EnvironmentVariable(`${key}-poison`, {
|