@fabrika/provider-zerops 0.0.4 → 0.0.5
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/package.json +5 -5
- package/src/api.ts +137 -12
- package/src/cli.ts +42 -2
- package/src/codec.ts +70 -12
- package/src/collaborators.ts +5 -0
- package/src/control.ts +302 -43
- package/src/index.ts +119 -1
- package/src/manifest.ts +60 -3
- package/src/provider.ts +171 -31
- package/src/source-connection.ts +394 -0
- package/src/source.ts +1043 -0
- package/src/types.ts +18 -1
package/src/control.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
ProviderDeploymentNamespace,
|
|
7
7
|
ProviderEnvelope,
|
|
8
8
|
ProviderEnvironment,
|
|
9
|
+
ProviderReconcileInput,
|
|
9
10
|
ProviderReconcileOutcome,
|
|
10
11
|
ProviderRegistration,
|
|
11
12
|
ProviderRegistrationInput,
|
|
@@ -14,12 +15,29 @@ import type {
|
|
|
14
15
|
RuntimeProviderRun,
|
|
15
16
|
SchemaReconciler,
|
|
16
17
|
} from '@fabrika/provider-contract'
|
|
17
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
createZeropsApi,
|
|
20
|
+
ZEROPS_ACTIVE,
|
|
21
|
+
ZEROPS_PROCESS_FINISHED,
|
|
22
|
+
ZEROPS_PROCESS_TERMINAL,
|
|
23
|
+
ZEROPS_TERMINAL,
|
|
24
|
+
type ZeropsApi,
|
|
25
|
+
ZeropsApiError,
|
|
26
|
+
type ZeropsAppVersion,
|
|
27
|
+
type ZeropsProcess,
|
|
28
|
+
} from './api'
|
|
18
29
|
import { defaultSleep, defaultZeropsCollaborators, type Sleeper } from './collaborators'
|
|
19
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
type FabrikaManifest,
|
|
32
|
+
parseFabrikaManifest,
|
|
33
|
+
renderFabrikaProvisioningYaml,
|
|
34
|
+
verifyZeropsArtifactSourceDescriptor,
|
|
35
|
+
zeropsArtifactCodec,
|
|
36
|
+
} from './manifest'
|
|
20
37
|
import { createZeropsNamespaceCapabilities, type ZeropsNamespaceTarget, zeropsNamespaceTargetCodec } from './namespace'
|
|
21
38
|
import { createZeropsProvider } from './provider'
|
|
22
|
-
import type
|
|
39
|
+
import { normalizeZeropsSourceRepository, type ZeropsSourceClient } from './source'
|
|
40
|
+
import type { ZeropsRunState, ZeropsRuntimeTarget } from './types'
|
|
23
41
|
|
|
24
42
|
/** Provider coordinates that are safe to persist. Credentials are composed only for a live run. */
|
|
25
43
|
export interface ZeropsStoredTarget {
|
|
@@ -91,8 +109,10 @@ export interface ZeropsControlProviderOptions {
|
|
|
91
109
|
readonly propustkaUrl?: string
|
|
92
110
|
readonly adminKey?: string
|
|
93
111
|
readonly api?: ZeropsApi
|
|
112
|
+
readonly source: ZeropsSourceClient
|
|
94
113
|
readonly reconcileSchema?: SchemaReconciler
|
|
95
114
|
readonly sleep?: Sleeper
|
|
115
|
+
readonly sourceCancelSleep?: Sleeper
|
|
96
116
|
readonly execute: ZeropsProviderExecutor
|
|
97
117
|
readonly beforeDeploy?: ZeropsBeforeDeploy
|
|
98
118
|
readonly namespaces?: {
|
|
@@ -185,6 +205,52 @@ const normalizeRegistration = (input: ProviderRegistrationInput): ProviderRegist
|
|
|
185
205
|
|
|
186
206
|
const abortSignal = (): AbortSignal => new AbortController().signal
|
|
187
207
|
|
|
208
|
+
const IMMUTABLE_GIT_OBJECT = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/
|
|
209
|
+
const BUILD_TRIGGER_CONSISTENCY_MS = 10_000
|
|
210
|
+
const SOURCE_CANCEL_TIMEOUT_MS = 5000
|
|
211
|
+
|
|
212
|
+
const parseRunState = (value: JsonValue | undefined, externalId: string): ZeropsRunState => {
|
|
213
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
214
|
+
throw new Error('Zerops run state must be an object')
|
|
215
|
+
}
|
|
216
|
+
const appVersionId = value['appVersionId']
|
|
217
|
+
const phase = value['phase']
|
|
218
|
+
if (typeof appVersionId !== 'string' || appVersionId === '' || appVersionId !== externalId) {
|
|
219
|
+
throw new Error('Zerops run state appVersionId must match the external id')
|
|
220
|
+
}
|
|
221
|
+
if (phase === 'version_created' || phase === 'source_uploaded' || phase === 'build_trigger_requested') {
|
|
222
|
+
if (Object.keys(value).some((key) => key !== 'appVersionId' && key !== 'phase')) {
|
|
223
|
+
throw new Error('Zerops run state contains an unknown field')
|
|
224
|
+
}
|
|
225
|
+
return { appVersionId, phase }
|
|
226
|
+
}
|
|
227
|
+
if (phase !== 'build_triggered') {
|
|
228
|
+
throw new Error('Zerops run state phase is invalid')
|
|
229
|
+
}
|
|
230
|
+
if (Object.keys(value).some((key) => key !== 'appVersionId' && key !== 'phase' && key !== 'processId')) {
|
|
231
|
+
throw new Error('Zerops run state contains an unknown field')
|
|
232
|
+
}
|
|
233
|
+
const processId = value['processId']
|
|
234
|
+
if (processId !== undefined && (typeof processId !== 'string' || processId === '')) {
|
|
235
|
+
throw new Error('Zerops run state processId must be a non-empty string when present')
|
|
236
|
+
}
|
|
237
|
+
return { appVersionId, phase, ...(processId === undefined ? {} : { processId }) }
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const runState = (
|
|
241
|
+
appVersionId: string,
|
|
242
|
+
phase: Exclude<ZeropsRunState['phase'], 'build_triggered'>,
|
|
243
|
+
): Exclude<ZeropsRunState, { phase: 'build_triggered' }> => ({ appVersionId, phase })
|
|
244
|
+
|
|
245
|
+
const buildTriggeredState = (
|
|
246
|
+
appVersionId: string,
|
|
247
|
+
processId?: string,
|
|
248
|
+
): Extract<ZeropsRunState, { phase: 'build_triggered' }> => ({
|
|
249
|
+
appVersionId,
|
|
250
|
+
phase: 'build_triggered',
|
|
251
|
+
...(processId === undefined ? {} : { processId }),
|
|
252
|
+
})
|
|
253
|
+
|
|
188
254
|
/** Build the complete Zerops lifecycle bundle without importing control-plane persistence. */
|
|
189
255
|
export const createZeropsControlProvider = (options: ZeropsControlProviderOptions): ControlProvider => {
|
|
190
256
|
if (options.accessToken === '') {
|
|
@@ -195,6 +261,8 @@ export const createZeropsControlProvider = (options: ZeropsControlProviderOption
|
|
|
195
261
|
const defaults = defaultZeropsCollaborators(target)
|
|
196
262
|
return {
|
|
197
263
|
api,
|
|
264
|
+
source: options.source,
|
|
265
|
+
...(options.sourceCancelSleep === undefined ? {} : { sourceCancelSleep: options.sourceCancelSleep }),
|
|
198
266
|
reconcileSchema: options.reconcileSchema ?? defaults.reconcileSchema,
|
|
199
267
|
sleep: options.sleep ?? defaultSleep,
|
|
200
268
|
}
|
|
@@ -207,9 +275,108 @@ export const createZeropsControlProvider = (options: ZeropsControlProviderOption
|
|
|
207
275
|
...(options.sleep !== undefined ? { sleep: options.sleep } : {}),
|
|
208
276
|
})
|
|
209
277
|
|
|
278
|
+
const artifactFor = (environment: ProviderEnvironment): FabrikaManifest =>
|
|
279
|
+
parseFabrikaManifest(
|
|
280
|
+
decodeEnvelope('artifact', environment.artifact, zeropsArtifactCodec),
|
|
281
|
+
{ appId: environment.appId, env: environment.env },
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
const cancelSourceBestEffort = async (runId: string, appVersionId: string): Promise<void> => {
|
|
285
|
+
const sourceController = new AbortController()
|
|
286
|
+
const timeoutController = new AbortController()
|
|
287
|
+
const cancel = Promise.resolve()
|
|
288
|
+
.then(() => options.source.cancel({ runId, appVersionId, signal: sourceController.signal }))
|
|
289
|
+
.catch(() => {})
|
|
290
|
+
const timeout = Promise.resolve()
|
|
291
|
+
.then(() => (options.sourceCancelSleep ?? defaultSleep)(SOURCE_CANCEL_TIMEOUT_MS, timeoutController.signal))
|
|
292
|
+
.then(() => sourceController.abort())
|
|
293
|
+
.catch(() => {})
|
|
294
|
+
await Promise.race([cancel, timeout])
|
|
295
|
+
timeoutController.abort()
|
|
296
|
+
sourceController.abort()
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const reconcileActiveSchema = async (
|
|
300
|
+
input: ProviderReconcileInput,
|
|
301
|
+
placement: ReturnType<typeof resolvedEnvironment>,
|
|
302
|
+
signal: AbortSignal,
|
|
303
|
+
): Promise<void> => {
|
|
304
|
+
const artifact = artifactFor(input.environment)
|
|
305
|
+
if (artifact.app.schema === undefined || options.propustkaUrl === undefined) return
|
|
306
|
+
const runtimeTarget: ZeropsRuntimeTarget = {
|
|
307
|
+
projectId: placement.projectId,
|
|
308
|
+
serviceId: placement.target.serviceId,
|
|
309
|
+
accessToken: options.accessToken,
|
|
310
|
+
...(options.apiBaseUrl !== undefined ? { apiBaseUrl: options.apiBaseUrl } : {}),
|
|
311
|
+
propustkaUrl: options.propustkaUrl,
|
|
312
|
+
...(options.adminKey !== undefined ? { adminKey: options.adminKey } : {}),
|
|
313
|
+
}
|
|
314
|
+
const reconcileSchema = options.reconcileSchema ?? defaultZeropsCollaborators(runtimeTarget).reconcileSchema
|
|
315
|
+
await reconcileSchema({
|
|
316
|
+
url: options.propustkaUrl,
|
|
317
|
+
app: artifact.app.id,
|
|
318
|
+
schema: artifact.app.schema,
|
|
319
|
+
...(input.returnOrigins === undefined || input.returnOrigins.length === 0 ? {} : { returnOrigins: input.returnOrigins }),
|
|
320
|
+
adminKey: options.adminKey,
|
|
321
|
+
signal,
|
|
322
|
+
})
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const reconcileTriggered = async (
|
|
326
|
+
input: ProviderReconcileInput,
|
|
327
|
+
state: Extract<ZeropsRunState, { phase: 'build_triggered' }>,
|
|
328
|
+
placement: ReturnType<typeof resolvedEnvironment>,
|
|
329
|
+
signal: AbortSignal,
|
|
330
|
+
): Promise<ProviderReconcileOutcome> => {
|
|
331
|
+
if (state.processId !== undefined) {
|
|
332
|
+
const process = await api.getProcess({ processId: state.processId, signal })
|
|
333
|
+
if (process.id !== state.processId) throw new Error('Zerops process response has different coordinates')
|
|
334
|
+
if (
|
|
335
|
+
process.status !== undefined
|
|
336
|
+
&& ZEROPS_PROCESS_TERMINAL.has(process.status)
|
|
337
|
+
&& process.status !== ZEROPS_PROCESS_FINISHED
|
|
338
|
+
) {
|
|
339
|
+
return { state: 'failed' }
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const version = await api.getAppVersion({ appVersionId: state.appVersionId, signal })
|
|
343
|
+
if (version.id !== state.appVersionId) throw new Error('Zerops app-version response has different coordinates')
|
|
344
|
+
if (version.status === ZEROPS_ACTIVE) {
|
|
345
|
+
await reconcileActiveSchema(input, placement, signal)
|
|
346
|
+
return { state: 'succeeded' }
|
|
347
|
+
}
|
|
348
|
+
if (version.status !== undefined && ZEROPS_TERMINAL.has(version.status)) return { state: 'failed' }
|
|
349
|
+
return { state: 'running' }
|
|
350
|
+
}
|
|
351
|
+
|
|
210
352
|
return {
|
|
211
353
|
id: 'zerops',
|
|
212
354
|
normalizeRegistration,
|
|
355
|
+
resolveSource: async (input) => {
|
|
356
|
+
const registration = normalizeRegistration({ app: input.app, environment: input.environment })
|
|
357
|
+
const artifact = decodeEnvelope('artifact', registration.environment.artifact, zeropsArtifactCodec)
|
|
358
|
+
await verifyZeropsArtifactSourceDescriptor(artifact.target.sourceDescriptor)
|
|
359
|
+
const repository = normalizeZeropsSourceRepository(registration.app.source.repoUrl)
|
|
360
|
+
const result = await options.source.resolve({
|
|
361
|
+
runId: input.runId,
|
|
362
|
+
repository,
|
|
363
|
+
requestedRef: registration.app.source.ref,
|
|
364
|
+
...(input.expectedCommitSha === undefined ? {} : { expectedCommitSha: input.expectedCommitSha }),
|
|
365
|
+
...(registration.app.source.githubInstallationId === undefined
|
|
366
|
+
? {}
|
|
367
|
+
: { githubInstallationId: registration.app.source.githubInstallationId }),
|
|
368
|
+
descriptorSha256: artifact.target.sourceDescriptor.sha256,
|
|
369
|
+
signal: input.signal,
|
|
370
|
+
})
|
|
371
|
+
if (
|
|
372
|
+
result.runId !== input.runId
|
|
373
|
+
|| result.descriptorSha256 !== artifact.target.sourceDescriptor.sha256
|
|
374
|
+
|| (input.expectedCommitSha !== undefined && result.commitSha !== input.expectedCommitSha)
|
|
375
|
+
) {
|
|
376
|
+
throw new Error('Zerops source resolution returned different coordinates')
|
|
377
|
+
}
|
|
378
|
+
return { commitSha: result.commitSha }
|
|
379
|
+
},
|
|
213
380
|
deploy: async (input: ProviderDeployInput): Promise<ProviderTerminalOutcome> => {
|
|
214
381
|
const registration = normalizeRegistration({ app: input.app, environment: input.environment })
|
|
215
382
|
const placement = resolvedEnvironment(registration.environment, { requireReady: true })
|
|
@@ -218,19 +385,36 @@ export const createZeropsControlProvider = (options: ZeropsControlProviderOption
|
|
|
218
385
|
throw new Error(`Zerops deployment namespace \`${placement.namespace.id}\` has no proxy service id`)
|
|
219
386
|
}
|
|
220
387
|
const artifact = decodeEnvelope('artifact', registration.environment.artifact, zeropsArtifactCodec)
|
|
221
|
-
await
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
388
|
+
await verifyZeropsArtifactSourceDescriptor(artifact.target.sourceDescriptor)
|
|
389
|
+
let source: ZeropsRuntimeTarget['source']
|
|
390
|
+
if (!input.dryRun) {
|
|
391
|
+
if (!IMMUTABLE_GIT_OBJECT.test(input.app.source.ref)) {
|
|
392
|
+
throw new Error('Zerops deploy source must be an exact lowercase Git object id')
|
|
393
|
+
}
|
|
394
|
+
source = {
|
|
395
|
+
runId: input.runId,
|
|
396
|
+
repository: normalizeZeropsSourceRepository(input.app.source.repoUrl),
|
|
397
|
+
commitSha: input.app.source.ref,
|
|
398
|
+
...(input.app.source.githubInstallationId === undefined
|
|
399
|
+
? {}
|
|
400
|
+
: { githubInstallationId: input.app.source.githubInstallationId }),
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (!input.dryRun) {
|
|
404
|
+
await options.beforeDeploy?.({
|
|
405
|
+
appId: input.app.id,
|
|
406
|
+
env: input.environment.env,
|
|
407
|
+
namespaceId: placement.namespace.id,
|
|
408
|
+
target: {
|
|
409
|
+
serviceId: placement.target.serviceId,
|
|
410
|
+
projectId: placement.projectId,
|
|
411
|
+
proxyServiceId,
|
|
412
|
+
},
|
|
413
|
+
artifact,
|
|
414
|
+
api,
|
|
415
|
+
signal: input.signal,
|
|
416
|
+
})
|
|
417
|
+
}
|
|
234
418
|
const managedEnvironment = input.managedEnvironment
|
|
235
419
|
const managedEntries = Object.entries(managedEnvironment).sort(([left], [right]) => left.localeCompare(right))
|
|
236
420
|
const managedNames = managedEntries.map(([name]) => name)
|
|
@@ -264,6 +448,7 @@ export const createZeropsControlProvider = (options: ZeropsControlProviderOption
|
|
|
264
448
|
projectId: placement.projectId,
|
|
265
449
|
serviceId: placement.target.serviceId,
|
|
266
450
|
accessToken: options.accessToken,
|
|
451
|
+
...(source === undefined ? {} : { source }),
|
|
267
452
|
...(options.apiBaseUrl !== undefined ? { apiBaseUrl: options.apiBaseUrl } : {}),
|
|
268
453
|
...(options.propustkaUrl !== undefined ? { propustkaUrl: options.propustkaUrl } : {}),
|
|
269
454
|
...(options.adminKey !== undefined ? { adminKey: options.adminKey } : {}),
|
|
@@ -286,42 +471,116 @@ export const createZeropsControlProvider = (options: ZeropsControlProviderOption
|
|
|
286
471
|
},
|
|
287
472
|
cancel: async (input) => {
|
|
288
473
|
resolvedEnvironment(input.environment, { requireReady: false })
|
|
289
|
-
|
|
474
|
+
const state = parseRunState(input.providerState, input.externalId)
|
|
475
|
+
await cancelSourceBestEffort(input.runId, state.appVersionId)
|
|
476
|
+
if (state.phase === 'build_triggered') {
|
|
477
|
+
await api.cancelBuild({ appVersionId: state.appVersionId, signal: abortSignal() })
|
|
478
|
+
return
|
|
479
|
+
}
|
|
480
|
+
if (state.phase === 'build_trigger_requested') {
|
|
481
|
+
await (options.sleep ?? defaultSleep)(BUILD_TRIGGER_CONSISTENCY_MS, abortSignal())
|
|
482
|
+
const version = await api.getAppVersion({ appVersionId: state.appVersionId, signal: abortSignal() })
|
|
483
|
+
if (version.id !== state.appVersionId) throw new Error('Zerops app-version response has different coordinates')
|
|
484
|
+
if (version.status === undefined) {
|
|
485
|
+
throw new Error('Zerops app-version status is not observable yet')
|
|
486
|
+
}
|
|
487
|
+
if (version.status !== 'UPLOADING') {
|
|
488
|
+
await api.cancelBuild({ appVersionId: state.appVersionId, signal: abortSignal() })
|
|
489
|
+
return
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
await api.deleteAppVersion({ appVersionId: state.appVersionId, signal: abortSignal() })
|
|
290
493
|
},
|
|
291
494
|
reconcile: async (input): Promise<ProviderReconcileOutcome> => {
|
|
292
495
|
const signal = abortSignal()
|
|
293
496
|
const placement = resolvedEnvironment(input.environment, { requireReady: false })
|
|
294
|
-
const
|
|
295
|
-
if (
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
497
|
+
const state = parseRunState(input.providerState, input.externalId)
|
|
498
|
+
if (state.phase === 'version_created') {
|
|
499
|
+
await cancelSourceBestEffort(input.runId, state.appVersionId)
|
|
500
|
+
await api.deleteAppVersion({ appVersionId: state.appVersionId, signal: abortSignal() })
|
|
501
|
+
return { state: 'failed' }
|
|
502
|
+
}
|
|
503
|
+
if (state.phase === 'source_uploaded') {
|
|
504
|
+
let artifact: FabrikaManifest
|
|
505
|
+
try {
|
|
506
|
+
artifact = artifactFor(input.environment)
|
|
507
|
+
await verifyZeropsArtifactSourceDescriptor(artifact.target.sourceDescriptor)
|
|
508
|
+
} catch {
|
|
509
|
+
await cancelSourceBestEffort(input.runId, state.appVersionId)
|
|
510
|
+
await api.deleteAppVersion({ appVersionId: state.appVersionId, signal: abortSignal() })
|
|
511
|
+
return { state: 'failed' }
|
|
512
|
+
}
|
|
513
|
+
try {
|
|
514
|
+
await input.checkpoint(runState(state.appVersionId, 'build_trigger_requested'))
|
|
515
|
+
} catch {
|
|
516
|
+
return { state: 'running' }
|
|
517
|
+
}
|
|
518
|
+
let process: ZeropsProcess
|
|
519
|
+
try {
|
|
520
|
+
process = await api.buildAndDeployAppVersion({
|
|
521
|
+
appVersionId: state.appVersionId,
|
|
522
|
+
zeropsYaml: artifact.target.sourceDescriptor.contents,
|
|
523
|
+
...(artifact.target.zeropsSetup === undefined ? {} : { zeropsYamlSetup: artifact.target.zeropsSetup }),
|
|
316
524
|
signal,
|
|
317
525
|
})
|
|
526
|
+
} catch (error) {
|
|
527
|
+
if (error instanceof ZeropsApiError && error.status >= 400 && error.status < 500) {
|
|
528
|
+
await cancelSourceBestEffort(input.runId, state.appVersionId)
|
|
529
|
+
await api.deleteAppVersion({ appVersionId: state.appVersionId, signal: abortSignal() })
|
|
530
|
+
return { state: 'failed' }
|
|
531
|
+
}
|
|
532
|
+
let observed: ZeropsAppVersion
|
|
533
|
+
try {
|
|
534
|
+
await (options.sleep ?? defaultSleep)(BUILD_TRIGGER_CONSISTENCY_MS, signal)
|
|
535
|
+
observed = await api.getAppVersion({ appVersionId: state.appVersionId, signal })
|
|
536
|
+
} catch {
|
|
537
|
+
return { state: 'running' }
|
|
538
|
+
}
|
|
539
|
+
if (observed.id !== state.appVersionId || observed.status === undefined) return { state: 'running' }
|
|
540
|
+
if (observed.status === 'UPLOADING') {
|
|
541
|
+
await cancelSourceBestEffort(input.runId, state.appVersionId)
|
|
542
|
+
await api.deleteAppVersion({ appVersionId: state.appVersionId, signal: abortSignal() })
|
|
543
|
+
return { state: 'failed' }
|
|
544
|
+
}
|
|
545
|
+
const triggered = buildTriggeredState(state.appVersionId)
|
|
546
|
+
try {
|
|
547
|
+
await input.checkpoint(triggered)
|
|
548
|
+
} catch {
|
|
549
|
+
return { state: 'running' }
|
|
550
|
+
}
|
|
551
|
+
return reconcileTriggered(input, triggered, placement, signal)
|
|
552
|
+
}
|
|
553
|
+
const triggered = buildTriggeredState(state.appVersionId, process.id)
|
|
554
|
+
try {
|
|
555
|
+
await input.checkpoint(triggered)
|
|
556
|
+
} catch {
|
|
557
|
+
return { state: 'running' }
|
|
318
558
|
}
|
|
319
|
-
return
|
|
559
|
+
return reconcileTriggered(input, triggered, placement, signal)
|
|
320
560
|
}
|
|
321
|
-
if (
|
|
322
|
-
|
|
561
|
+
if (state.phase === 'build_trigger_requested') {
|
|
562
|
+
let version: ZeropsAppVersion
|
|
563
|
+
try {
|
|
564
|
+
await (options.sleep ?? defaultSleep)(BUILD_TRIGGER_CONSISTENCY_MS, signal)
|
|
565
|
+
version = await api.getAppVersion({ appVersionId: state.appVersionId, signal })
|
|
566
|
+
} catch {
|
|
567
|
+
return { state: 'running' }
|
|
568
|
+
}
|
|
569
|
+
if (version.id !== state.appVersionId || version.status === undefined) return { state: 'running' }
|
|
570
|
+
if (version.status === 'UPLOADING') {
|
|
571
|
+
await cancelSourceBestEffort(input.runId, state.appVersionId)
|
|
572
|
+
await api.deleteAppVersion({ appVersionId: state.appVersionId, signal: abortSignal() })
|
|
573
|
+
return { state: 'failed' }
|
|
574
|
+
}
|
|
575
|
+
const triggered = buildTriggeredState(state.appVersionId)
|
|
576
|
+
try {
|
|
577
|
+
await input.checkpoint(triggered)
|
|
578
|
+
} catch {
|
|
579
|
+
return { state: 'running' }
|
|
580
|
+
}
|
|
581
|
+
return reconcileTriggered(input, triggered, placement, signal)
|
|
323
582
|
}
|
|
324
|
-
return
|
|
583
|
+
return reconcileTriggered(input, state, placement, signal)
|
|
325
584
|
},
|
|
326
585
|
secrets: {
|
|
327
586
|
put: async (input) => {
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ export type {
|
|
|
16
16
|
ZeropsApiOptions,
|
|
17
17
|
ZeropsAppVersion,
|
|
18
18
|
ZeropsAppVersionStatus,
|
|
19
|
+
ZeropsAppVersionUpload,
|
|
19
20
|
ZeropsImportedService,
|
|
20
21
|
ZeropsImportResult,
|
|
21
22
|
ZeropsIntegrationToken,
|
|
@@ -53,14 +54,17 @@ export { createZeropsControlProvider, zeropsStoredTargetCodec } from './control'
|
|
|
53
54
|
export type { ZeropsBeforeDeploy, ZeropsBeforeDeployInput, ZeropsControlProviderOptions, ZeropsProviderExecutor, ZeropsStoredTarget } from './control'
|
|
54
55
|
export {
|
|
55
56
|
compileFabrikaManifest,
|
|
57
|
+
createZeropsArtifactSourceDescriptor,
|
|
56
58
|
FABRIKA_MANIFEST_VERSION,
|
|
57
59
|
manifestServiceHostnames,
|
|
58
60
|
parseFabrikaManifest,
|
|
59
61
|
renderFabrikaImportYaml,
|
|
62
|
+
verifyZeropsArtifactSourceDescriptor,
|
|
60
63
|
ZEROPS_SERVICE_HOSTNAME_PATTERN,
|
|
64
|
+
ZEROPS_SOURCE_DESCRIPTOR_MAX_BYTES,
|
|
61
65
|
zeropsArtifactCodec,
|
|
62
66
|
} from './manifest'
|
|
63
|
-
export type { FabrikaImportDocument, FabrikaManifest, ManifestExpectation } from './manifest'
|
|
67
|
+
export type { FabrikaImportDocument, FabrikaManifest, ManifestExpectation, ZeropsArtifactSourceDescriptor } from './manifest'
|
|
64
68
|
export {
|
|
65
69
|
compileZeropsNamespaceTopology,
|
|
66
70
|
createZeropsNamespaceCapabilities,
|
|
@@ -90,6 +94,118 @@ export type { ZeropsJobSpec, ZeropsPlan, ZeropsStepKind } from './plan'
|
|
|
90
94
|
export { CANCELLED, createZeropsProvider, interpolateManifest, zeropsProvider } from './provider'
|
|
91
95
|
export type { ZeropsProvider } from './provider'
|
|
92
96
|
export type * from './schema.generated'
|
|
97
|
+
export {
|
|
98
|
+
buildZeropsSourceCancelRequest,
|
|
99
|
+
buildZeropsSourceCancelResponse,
|
|
100
|
+
buildZeropsSourceCredentialActivateRequest,
|
|
101
|
+
buildZeropsSourceCredentialActivateResponse,
|
|
102
|
+
buildZeropsSourceCredentialBundle,
|
|
103
|
+
buildZeropsSourceCredentialStatusRequest,
|
|
104
|
+
buildZeropsSourceCredentialStatusResponse,
|
|
105
|
+
buildZeropsSourceErrorEnvelope,
|
|
106
|
+
buildZeropsSourceInstallationsVerifyRequest,
|
|
107
|
+
buildZeropsSourceInstallationsVerifyResponse,
|
|
108
|
+
buildZeropsSourceResolveInstallationRequest,
|
|
109
|
+
buildZeropsSourceResolveInstallationResponse,
|
|
110
|
+
buildZeropsSourceResolveRequest,
|
|
111
|
+
buildZeropsSourceResolveResponse,
|
|
112
|
+
buildZeropsSourceUploadRequest,
|
|
113
|
+
buildZeropsSourceUploadResponse,
|
|
114
|
+
buildZeropsSourceWebhookConfigureRequest,
|
|
115
|
+
buildZeropsSourceWebhookConfigureResponse,
|
|
116
|
+
decodeZeropsSourceCancelRequest,
|
|
117
|
+
decodeZeropsSourceCancelResponse,
|
|
118
|
+
decodeZeropsSourceCredentialActivateRequest,
|
|
119
|
+
decodeZeropsSourceCredentialActivateResponse,
|
|
120
|
+
decodeZeropsSourceCredentialBundle,
|
|
121
|
+
decodeZeropsSourceCredentialStatusRequest,
|
|
122
|
+
decodeZeropsSourceCredentialStatusResponse,
|
|
123
|
+
decodeZeropsSourceErrorEnvelope,
|
|
124
|
+
decodeZeropsSourceInstallationsVerifyRequest,
|
|
125
|
+
decodeZeropsSourceInstallationsVerifyResponse,
|
|
126
|
+
decodeZeropsSourceResolveInstallationRequest,
|
|
127
|
+
decodeZeropsSourceResolveInstallationResponse,
|
|
128
|
+
decodeZeropsSourceResolveRequest,
|
|
129
|
+
decodeZeropsSourceResolveResponse,
|
|
130
|
+
decodeZeropsSourceUploadRequest,
|
|
131
|
+
decodeZeropsSourceUploadResponse,
|
|
132
|
+
decodeZeropsSourceWebhookConfigureRequest,
|
|
133
|
+
decodeZeropsSourceWebhookConfigureResponse,
|
|
134
|
+
normalizeZeropsSourceRepository,
|
|
135
|
+
serializeZeropsSourceCredentialBundle,
|
|
136
|
+
sha256ZeropsSourceCredentialBundle,
|
|
137
|
+
ZEROPS_SOURCE_CANCEL_PATH,
|
|
138
|
+
ZEROPS_SOURCE_CREDENTIAL_ACTIVATE_PATH,
|
|
139
|
+
ZEROPS_SOURCE_CREDENTIAL_BUNDLE_VERSION,
|
|
140
|
+
ZEROPS_SOURCE_CREDENTIAL_STATUS_PATH,
|
|
141
|
+
ZEROPS_SOURCE_ERROR_CODES,
|
|
142
|
+
ZEROPS_SOURCE_ERROR_STAGES,
|
|
143
|
+
ZEROPS_SOURCE_INSTALLATIONS_VERIFY_PATH,
|
|
144
|
+
ZEROPS_SOURCE_PROTOCOL_VERSION,
|
|
145
|
+
ZEROPS_SOURCE_RESOLVE_INSTALLATION_PATH,
|
|
146
|
+
ZEROPS_SOURCE_RESOLVE_PATH,
|
|
147
|
+
ZEROPS_SOURCE_UPLOAD_PATH,
|
|
148
|
+
ZEROPS_SOURCE_WEBHOOK_CONFIGURE_PATH,
|
|
149
|
+
} from './source'
|
|
150
|
+
export type {
|
|
151
|
+
ZeropsSourceCancelInput,
|
|
152
|
+
ZeropsSourceCancelRequestV1,
|
|
153
|
+
ZeropsSourceCancelResponseV1,
|
|
154
|
+
ZeropsSourceCancelResult,
|
|
155
|
+
ZeropsSourceClient,
|
|
156
|
+
ZeropsSourceCredentialActivateInput,
|
|
157
|
+
ZeropsSourceCredentialActivateRequestV1,
|
|
158
|
+
ZeropsSourceCredentialActivateResponseV1,
|
|
159
|
+
ZeropsSourceCredentialActiveStatusResponseV1,
|
|
160
|
+
ZeropsSourceCredentialAnonymousStatusResponseV1,
|
|
161
|
+
ZeropsSourceCredentialBundleV1,
|
|
162
|
+
ZeropsSourceCredentialManager,
|
|
163
|
+
ZeropsSourceCredentialStatusInput,
|
|
164
|
+
ZeropsSourceCredentialStatusRequestV1,
|
|
165
|
+
ZeropsSourceCredentialStatusResponseV1,
|
|
166
|
+
ZeropsSourceDescriptor,
|
|
167
|
+
ZeropsSourceErrorCode,
|
|
168
|
+
ZeropsSourceErrorEnvelope,
|
|
169
|
+
ZeropsSourceErrorStage,
|
|
170
|
+
ZeropsSourceGitHubAppIdentityV1,
|
|
171
|
+
ZeropsSourceInstallationScopeV1,
|
|
172
|
+
ZeropsSourceInstallationsVerifyInput,
|
|
173
|
+
ZeropsSourceInstallationsVerifyRequestV1,
|
|
174
|
+
ZeropsSourceInstallationsVerifyResponseV1,
|
|
175
|
+
ZeropsSourceInstallationVerificationV1,
|
|
176
|
+
ZeropsSourceRepository,
|
|
177
|
+
ZeropsSourceResolveInput,
|
|
178
|
+
ZeropsSourceResolveInstallationRequestV1,
|
|
179
|
+
ZeropsSourceResolveInstallationResponseV1,
|
|
180
|
+
ZeropsSourceResolveRequestV1,
|
|
181
|
+
ZeropsSourceResolveResponseV1,
|
|
182
|
+
ZeropsSourceResolveResult,
|
|
183
|
+
ZeropsSourceUploadInput,
|
|
184
|
+
ZeropsSourceUploadRequestV1,
|
|
185
|
+
ZeropsSourceUploadResponseV1,
|
|
186
|
+
ZeropsSourceUploadResult,
|
|
187
|
+
ZeropsSourceWebhookConfigureInput,
|
|
188
|
+
ZeropsSourceWebhookConfigureRequestV1,
|
|
189
|
+
ZeropsSourceWebhookConfigureResponseV1,
|
|
190
|
+
} from './source'
|
|
191
|
+
export {
|
|
192
|
+
createZeropsSourceConnectionAdmin,
|
|
193
|
+
SourceConnectionAdminError,
|
|
194
|
+
ZEROPS_SOURCE_CREDENTIAL_ENV,
|
|
195
|
+
ZEROPS_SOURCE_LEGACY_APP_ID_ENV,
|
|
196
|
+
ZEROPS_SOURCE_LEGACY_PRIVATE_KEY_ENV,
|
|
197
|
+
} from './source-connection'
|
|
198
|
+
export type {
|
|
199
|
+
SourceConnectionActivateInput,
|
|
200
|
+
SourceConnectionAdmin,
|
|
201
|
+
SourceConnectionAdminErrorCode,
|
|
202
|
+
SourceConnectionAdoptExistingInput,
|
|
203
|
+
SourceConnectionInspection,
|
|
204
|
+
SourceConnectionStatus,
|
|
205
|
+
SourceConnectionStatusInput,
|
|
206
|
+
SourceConnectionZeropsApi,
|
|
207
|
+
ZeropsSourceConnectionAdminOptions,
|
|
208
|
+
} from './source-connection'
|
|
93
209
|
export type {
|
|
94
210
|
ZeropsAppConfig,
|
|
95
211
|
ZeropsCompilerOwnedProjectField,
|
|
@@ -101,6 +217,8 @@ export type {
|
|
|
101
217
|
ZeropsProxySpec,
|
|
102
218
|
ZeropsReadinessCheckSpec,
|
|
103
219
|
ZeropsResourceContext,
|
|
220
|
+
ZeropsRunState,
|
|
221
|
+
ZeropsRuntimeSource,
|
|
104
222
|
ZeropsRuntimeTarget,
|
|
105
223
|
ZeropsServiceSpec,
|
|
106
224
|
ZeropsSharedPostgresBinding,
|