@shipfox/api-definitions 11.0.0 → 12.2.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/.turbo/turbo-build.log +13 -12
- package/CHANGELOG.md +106 -0
- package/dist/core/entities/index.d.ts +1 -0
- package/dist/core/entities/index.d.ts.map +1 -1
- package/dist/core/entities/index.js +1 -0
- package/dist/core/entities/index.js.map +1 -1
- package/dist/core/entities/sync-state.d.ts +5 -1
- package/dist/core/entities/sync-state.d.ts.map +1 -1
- package/dist/core/entities/sync-state.js +10 -0
- package/dist/core/entities/sync-state.js.map +1 -1
- package/dist/core/entities/validation-warning.d.ts +6 -0
- package/dist/core/entities/validation-warning.d.ts.map +1 -0
- package/dist/core/entities/validation-warning.js +3 -0
- package/dist/core/entities/validation-warning.js.map +1 -0
- package/dist/core/errors.d.ts +2 -2
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/integrations.d.ts +1 -1
- package/dist/core/parse-definition.d.ts +9 -7
- package/dist/core/parse-definition.d.ts.map +1 -1
- package/dist/core/parse-definition.js +14 -2
- package/dist/core/parse-definition.js.map +1 -1
- package/dist/core/sync-definitions.d.ts +2 -0
- package/dist/core/sync-definitions.d.ts.map +1 -1
- package/dist/core/sync-definitions.js +6 -5
- package/dist/core/sync-definitions.js.map +1 -1
- package/dist/core/validate-definition.d.ts +9 -5
- package/dist/core/validate-definition.d.ts.map +1 -1
- package/dist/core/validate-definition.js +23 -2
- package/dist/core/validate-definition.js.map +1 -1
- package/dist/core/workflow-model/index.d.ts +1 -1
- package/dist/core/workflow-model/index.d.ts.map +1 -1
- package/dist/core/workflow-model/index.js.map +1 -1
- package/dist/core/workflow-model/invalid-workflow-model-error.d.ts +3 -1
- package/dist/core/workflow-model/invalid-workflow-model-error.d.ts.map +1 -1
- package/dist/core/workflow-model/invalid-workflow-model-error.js.map +1 -1
- package/dist/core/workflow-model/normalize-if-condition.d.ts +0 -1
- package/dist/core/workflow-model/normalize-if-condition.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-if-condition.js +0 -1
- package/dist/core/workflow-model/normalize-if-condition.js.map +1 -1
- package/dist/core/workflow-model/normalize-job-checkout.d.ts +15 -3
- package/dist/core/workflow-model/normalize-job-checkout.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-job-checkout.js +83 -4
- package/dist/core/workflow-model/normalize-job-checkout.js.map +1 -1
- package/dist/core/workflow-model/normalize-job-listening.js +0 -1
- package/dist/core/workflow-model/normalize-job-listening.js.map +1 -1
- package/dist/core/workflow-model/normalize-job-success.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-job-success.js +0 -1
- package/dist/core/workflow-model/normalize-job-success.js.map +1 -1
- package/dist/core/workflow-model/normalize-jobs.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-jobs.js +315 -74
- package/dist/core/workflow-model/normalize-jobs.js.map +1 -1
- package/dist/core/workflow-model/normalize-step-gate.js +0 -1
- package/dist/core/workflow-model/normalize-step-gate.js.map +1 -1
- package/dist/core/workflow-model/normalize-triggers.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-triggers.js +0 -1
- package/dist/core/workflow-model/normalize-triggers.js.map +1 -1
- package/dist/core/workflow-model/normalize-workflow-document.d.ts +3 -0
- package/dist/core/workflow-model/normalize-workflow-document.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-workflow-document.js +34 -4
- package/dist/core/workflow-model/normalize-workflow-document.js.map +1 -1
- package/dist/core/workflow-model/parse-interpolation-field.d.ts +1 -1
- package/dist/core/workflow-model/parse-interpolation-field.d.ts.map +1 -1
- package/dist/core/workflow-model/parse-interpolation-field.js +27 -57
- package/dist/core/workflow-model/parse-interpolation-field.js.map +1 -1
- package/dist/core/workflow-model/validate-literal-name.d.ts +12 -0
- package/dist/core/workflow-model/validate-literal-name.d.ts.map +1 -0
- package/dist/core/workflow-model/validate-literal-name.js +36 -0
- package/dist/core/workflow-model/validate-literal-name.js.map +1 -0
- package/dist/core/workflow-model/validate-predicate-expression.d.ts +1 -2
- package/dist/core/workflow-model/validate-predicate-expression.d.ts.map +1 -1
- package/dist/core/workflow-model/validate-predicate-expression.js +31 -90
- package/dist/core/workflow-model/validate-predicate-expression.js.map +1 -1
- package/dist/core/workflow-model/validation-issue.d.ts +2 -1
- package/dist/core/workflow-model/validation-issue.d.ts.map +1 -1
- package/dist/core/workflow-model/validation-issue.js +8 -2
- package/dist/core/workflow-model/validation-issue.js.map +1 -1
- package/dist/core/workflow-model/workflow-field-label.d.ts.map +1 -1
- package/dist/core/workflow-model/workflow-field-label.js +16 -2
- package/dist/core/workflow-model/workflow-field-label.js.map +1 -1
- package/dist/core/workflow-yaml/invalid-workflow-yaml-error.d.ts.map +1 -1
- package/dist/db/db.d.ts +48 -10
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/schema/definitions.d.ts +1 -1
- package/dist/db/schema/outbox.d.ts +1 -1
- package/dist/db/schema/sync-states.d.ts +22 -3
- package/dist/db/schema/sync-states.d.ts.map +1 -1
- package/dist/db/schema/sync-states.js +3 -1
- package/dist/db/schema/sync-states.js.map +1 -1
- package/dist/db/sync-states.d.ts +2 -1
- package/dist/db/sync-states.d.ts.map +1 -1
- package/dist/db/sync-states.js +4 -0
- package/dist/db/sync-states.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/presentation/dto/definition.d.ts.map +1 -1
- package/dist/presentation/dto/definition.js +2 -1
- package/dist/presentation/dto/definition.js.map +1 -1
- package/dist/presentation/routes/project-access.d.ts +1 -0
- package/dist/presentation/routes/project-access.d.ts.map +1 -1
- package/dist/presentation/routes/validate-definition.d.ts.map +1 -1
- package/dist/presentation/routes/validate-definition.js +5 -3
- package/dist/presentation/routes/validate-definition.js.map +1 -1
- package/dist/presentation/subscribers/index.d.ts +1 -0
- package/dist/presentation/subscribers/index.d.ts.map +1 -1
- package/dist/presentation/subscribers/index.js +1 -0
- package/dist/presentation/subscribers/index.js.map +1 -1
- package/dist/presentation/subscribers/on-integration-connection-available.d.ts +5 -0
- package/dist/presentation/subscribers/on-integration-connection-available.d.ts.map +1 -0
- package/dist/presentation/subscribers/on-integration-connection-available.js +32 -0
- package/dist/presentation/subscribers/on-integration-connection-available.js.map +1 -0
- package/dist/presentation/subscribers/start-definition-sync.d.ts +1 -0
- package/dist/presentation/subscribers/start-definition-sync.d.ts.map +1 -1
- package/dist/presentation/subscribers/start-definition-sync.js +30 -17
- package/dist/presentation/subscribers/start-definition-sync.js.map +1 -1
- package/dist/temporal/activities/sync-activities.d.ts +6 -2
- package/dist/temporal/activities/sync-activities.d.ts.map +1 -1
- package/dist/temporal/activities/sync-activities.js +8 -1
- package/dist/temporal/activities/sync-activities.js.map +1 -1
- package/dist/temporal/workflows/definition-sync.js +4 -1
- package/dist/temporal/workflows/definition-sync.js.map +1 -1
- package/dist/temporal/workflows/index.bundle.js +9029 -3
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0002_lumpy_ben_parker.sql +1 -0
- package/drizzle/meta/0002_snapshot.json +534 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +17 -17
- package/src/core/entities/index.ts +1 -0
- package/src/core/entities/sync-state.ts +23 -0
- package/src/core/entities/validation-warning.ts +5 -0
- package/src/core/parse-definition-warnings.test.ts +33 -0
- package/src/core/parse-definition.test.ts +7 -1
- package/src/core/parse-definition.ts +28 -10
- package/src/core/sync-definitions.test.ts +39 -0
- package/src/core/sync-definitions.ts +14 -4
- package/src/core/validate-definition.test.ts +128 -0
- package/src/core/validate-definition.ts +39 -8
- package/src/core/workflow-model/README.md +2 -2
- package/src/core/workflow-model/index.ts +1 -0
- package/src/core/workflow-model/invalid-workflow-model-error.ts +8 -3
- package/src/core/workflow-model/normalize-if-condition.ts +0 -2
- package/src/core/workflow-model/normalize-job-checkout.ts +105 -8
- package/src/core/workflow-model/normalize-job-listening.ts +0 -1
- package/src/core/workflow-model/normalize-job-success.ts +0 -1
- package/src/core/workflow-model/normalize-jobs.ts +335 -90
- package/src/core/workflow-model/normalize-step-gate.ts +0 -1
- package/src/core/workflow-model/normalize-triggers.ts +0 -1
- package/src/core/workflow-model/normalize-workflow-document.test.ts +876 -202
- package/src/core/workflow-model/normalize-workflow-document.ts +29 -4
- package/src/core/workflow-model/parse-interpolation-field.ts +50 -79
- package/src/core/workflow-model/validate-literal-name.ts +64 -0
- package/src/core/workflow-model/validate-predicate-expression.test.ts +153 -15
- package/src/core/workflow-model/validate-predicate-expression.ts +52 -120
- package/src/core/workflow-model/validation-issue.ts +4 -0
- package/src/core/workflow-model/workflow-field-label.ts +16 -2
- package/src/core/workflow-yaml/README.md +2 -2
- package/src/db/schema/sync-states.ts +4 -1
- package/src/db/sync-states.test.ts +57 -0
- package/src/db/sync-states.ts +6 -0
- package/src/index.ts +12 -1
- package/src/presentation/dto/definition.ts +1 -0
- package/src/presentation/routes/list-definitions.test.ts +1 -0
- package/src/presentation/routes/validate-definition.test.ts +1 -0
- package/src/presentation/routes/validate-definition.ts +7 -1
- package/src/presentation/subscribers/index.ts +1 -0
- package/src/presentation/subscribers/on-integration-connection-available.test.ts +132 -0
- package/src/presentation/subscribers/on-integration-connection-available.ts +44 -0
- package/src/presentation/subscribers/start-definition-sync.ts +35 -19
- package/src/temporal/activities/sync-activities.test.ts +16 -0
- package/src/temporal/activities/sync-activities.ts +18 -3
- package/src/temporal/workflows/definition-sync.ts +1 -1
- package/test/agent-validation-catalog.ts +17 -0
- package/test/fixtures/valid-listening-job.yml +2 -1
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AvailabilitySite,
|
|
3
|
-
analyzeContextRootKeyAccess,
|
|
4
|
-
availabilitySites,
|
|
5
3
|
createWorkflowExpression,
|
|
4
|
+
type ExpressionType,
|
|
6
5
|
type ExpressionTypeEnvironment,
|
|
7
6
|
extractExactContextRoots,
|
|
8
7
|
getWorkflowContextDefinition,
|
|
9
|
-
|
|
8
|
+
getWorkflowPredicateContextRoots,
|
|
9
|
+
getWorkflowPredicateFieldMinimumFillTarget,
|
|
10
|
+
getWorkflowPredicateFieldTypeEnvironment,
|
|
10
11
|
InvalidWorkflowExpressionError,
|
|
11
12
|
predicateSourceIsBooleanShaped,
|
|
12
|
-
resolveContextRootAvailability,
|
|
13
13
|
resolveContextRootHost,
|
|
14
|
-
routeExpression,
|
|
15
14
|
validateServerEvaluable,
|
|
16
15
|
type WorkflowContextName,
|
|
17
16
|
type WorkflowExpression,
|
|
@@ -30,7 +29,6 @@ import {workflowFieldLabel} from './workflow-field-label.js';
|
|
|
30
29
|
export function validatePredicateExpression(params: {
|
|
31
30
|
field: WorkflowPredicateField;
|
|
32
31
|
source: string;
|
|
33
|
-
site: AvailabilitySite;
|
|
34
32
|
path: readonly WorkflowModelValidationIssuePathSegment[];
|
|
35
33
|
invalidCode: WorkflowModelValidationIssueCode;
|
|
36
34
|
invalidMessage: string;
|
|
@@ -38,6 +36,7 @@ export function validatePredicateExpression(params: {
|
|
|
38
36
|
allowedJobReferences?: ReadonlySet<string>;
|
|
39
37
|
typeOverlay?: ExpressionTypeEnvironment | undefined;
|
|
40
38
|
}): WorkflowExpression | undefined {
|
|
39
|
+
const site = getWorkflowPredicateFieldMinimumFillTarget(params.field);
|
|
41
40
|
const syntaxExpression = createSyntaxExpression(params);
|
|
42
41
|
if (syntaxExpression === undefined) return undefined;
|
|
43
42
|
|
|
@@ -56,6 +55,7 @@ export function validatePredicateExpression(params: {
|
|
|
56
55
|
...serverEvaluability.violations.map((violation) =>
|
|
57
56
|
runnerContextInServerPredicateIssue({
|
|
58
57
|
...params,
|
|
58
|
+
site,
|
|
59
59
|
contextRoots,
|
|
60
60
|
runnerRoots: violation.runnerRoots,
|
|
61
61
|
}),
|
|
@@ -64,35 +64,18 @@ export function validatePredicateExpression(params: {
|
|
|
64
64
|
return undefined;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const unavailableRoots = knownRoots.filter((root) => !isRootAvailableAt(root, params.site));
|
|
67
|
+
const predicateContextRoots = getWorkflowPredicateContextRoots(params.field);
|
|
68
|
+
const unavailableRoots = knownRoots.filter(
|
|
69
|
+
(root) => !predicateContextRoots.includes(root as (typeof predicateContextRoots)[number]),
|
|
70
|
+
);
|
|
74
71
|
if (unavailableRoots.length > 0) {
|
|
75
72
|
params.issues.push(
|
|
76
|
-
unavailablePredicateContextIssue({
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (route.fillTarget !== 'runner-fill' && !isSiteAtOrAfter(params.site, route.fillTarget)) {
|
|
83
|
-
const unavailableRoots = unavailableRouteReferences(syntaxExpression);
|
|
84
|
-
params.issues.push(
|
|
85
|
-
unavailableRoots.length > 0
|
|
86
|
-
? unavailablePredicateContextIssue({
|
|
87
|
-
...params,
|
|
88
|
-
contextRoots,
|
|
89
|
-
unavailableRoots,
|
|
90
|
-
})
|
|
91
|
-
: routeUnavailablePredicateContextIssue({
|
|
92
|
-
...params,
|
|
93
|
-
contextRoots,
|
|
94
|
-
fillTarget: route.fillTarget,
|
|
95
|
-
}),
|
|
73
|
+
unavailablePredicateContextIssue({
|
|
74
|
+
...params,
|
|
75
|
+
site,
|
|
76
|
+
contextRoots,
|
|
77
|
+
unavailableRoots,
|
|
78
|
+
}),
|
|
96
79
|
);
|
|
97
80
|
return undefined;
|
|
98
81
|
}
|
|
@@ -112,7 +95,11 @@ export function validatePredicateExpression(params: {
|
|
|
112
95
|
return undefined;
|
|
113
96
|
}
|
|
114
97
|
|
|
115
|
-
if (
|
|
98
|
+
if (
|
|
99
|
+
params.typeOverlay === undefined &&
|
|
100
|
+
knownRoots.length > 0 &&
|
|
101
|
+
knownRoots.every((root) => hasSyntaxOnlyCheckMode(root))
|
|
102
|
+
) {
|
|
116
103
|
if (
|
|
117
104
|
isWorkflowFilterPredicateField(params.field) &&
|
|
118
105
|
!predicateSourceIsBooleanShaped(syntaxExpression.source)
|
|
@@ -137,7 +124,7 @@ export function validatePredicateExpression(params: {
|
|
|
137
124
|
mode: 'typed',
|
|
138
125
|
// `undefined` preserves the legacy syntax-only path above. `{}` means
|
|
139
126
|
// callers intentionally requested typed checking with the standard roots.
|
|
140
|
-
typeEnvironment: mergeTypeEnvironments(knownRoots, params.typeOverlay),
|
|
127
|
+
typeEnvironment: mergeTypeEnvironments(params.field, knownRoots, params.typeOverlay),
|
|
141
128
|
expectedResultType: 'bool',
|
|
142
129
|
},
|
|
143
130
|
});
|
|
@@ -241,27 +228,6 @@ function runnerContextInServerPredicateIssue(params: {
|
|
|
241
228
|
});
|
|
242
229
|
}
|
|
243
230
|
|
|
244
|
-
function varsContextInServerPredicateIssue(params: {
|
|
245
|
-
field: WorkflowPredicateField;
|
|
246
|
-
source: string;
|
|
247
|
-
site: AvailabilitySite;
|
|
248
|
-
path: readonly WorkflowModelValidationIssuePathSegment[];
|
|
249
|
-
contextRoots: readonly string[];
|
|
250
|
-
}): WorkflowModelValidationIssue {
|
|
251
|
-
return issue({
|
|
252
|
-
code: 'vars-context-in-server-predicate',
|
|
253
|
-
message: `${fieldLabel(params.field)} cannot reference vars because predicate evaluation does not include workflow variables.`,
|
|
254
|
-
path: params.path,
|
|
255
|
-
details: {
|
|
256
|
-
field: params.field,
|
|
257
|
-
source: params.source,
|
|
258
|
-
contextRoots: params.contextRoots,
|
|
259
|
-
rejectedRoots: ['vars'],
|
|
260
|
-
site: params.site,
|
|
261
|
-
},
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
231
|
function unavailablePredicateContextIssue(params: {
|
|
266
232
|
field: WorkflowPredicateField;
|
|
267
233
|
source: string;
|
|
@@ -276,9 +242,9 @@ function unavailablePredicateContextIssue(params: {
|
|
|
276
242
|
params.unavailableRoots,
|
|
277
243
|
)} ${formatList(params.unavailableRoots)} that ${availabilityVerb(
|
|
278
244
|
params.unavailableRoots,
|
|
279
|
-
)} not
|
|
280
|
-
.
|
|
281
|
-
|
|
245
|
+
)} not supplied when ${fieldLabel(params.field)} is evaluated at ${describeAvailabilitySite(
|
|
246
|
+
params.site,
|
|
247
|
+
)}.`,
|
|
282
248
|
path: params.path,
|
|
283
249
|
details: {
|
|
284
250
|
field: params.field,
|
|
@@ -290,60 +256,13 @@ function unavailablePredicateContextIssue(params: {
|
|
|
290
256
|
});
|
|
291
257
|
}
|
|
292
258
|
|
|
293
|
-
function routeUnavailablePredicateContextIssue(params: {
|
|
294
|
-
field: WorkflowPredicateField;
|
|
295
|
-
source: string;
|
|
296
|
-
site: AvailabilitySite;
|
|
297
|
-
path: readonly WorkflowModelValidationIssuePathSegment[];
|
|
298
|
-
contextRoots: readonly string[];
|
|
299
|
-
fillTarget: AvailabilitySite;
|
|
300
|
-
}): WorkflowModelValidationIssue {
|
|
301
|
-
return issue({
|
|
302
|
-
code: 'context-unavailable-at-predicate-site',
|
|
303
|
-
message: `${fieldLabel(params.field)} requires context filled at ${describeAvailabilitySite(
|
|
304
|
-
params.fillTarget,
|
|
305
|
-
)}, but it is evaluated at ${describeAvailabilitySite(params.site)}.`,
|
|
306
|
-
path: params.path,
|
|
307
|
-
details: {
|
|
308
|
-
field: params.field,
|
|
309
|
-
source: params.source,
|
|
310
|
-
contextRoots: params.contextRoots,
|
|
311
|
-
fillTarget: params.fillTarget,
|
|
312
|
-
site: params.site,
|
|
313
|
-
},
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
function isRootAvailableAt(root: string, site: AvailabilitySite): boolean {
|
|
318
|
-
const availability = resolveContextRootAvailability(root);
|
|
319
|
-
if (availability === undefined) return false;
|
|
320
|
-
|
|
321
|
-
return availabilitySites.indexOf(availability) <= availabilitySites.indexOf(site);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
function unavailableRootAvailabilityMessage(root: string): string {
|
|
325
|
-
if (root === 'execution.failed') {
|
|
326
|
-
return '"execution.failed" becomes available at step dispatch.';
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
const availability = resolveContextRootAvailability(root);
|
|
330
|
-
if (availability === undefined) return `"${root}" is not available at any server site.`;
|
|
331
|
-
return `"${root}" becomes available at ${describeAvailabilitySite(availability)}.`;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
function unavailableRouteReferences(expression: WorkflowExpression): readonly string[] {
|
|
335
|
-
const access = analyzeContextRootKeyAccess(expression, ['execution']);
|
|
336
|
-
return access.references.some((reference) => reference.key === 'failed')
|
|
337
|
-
? ['execution.failed']
|
|
338
|
-
: [];
|
|
339
|
-
}
|
|
340
|
-
|
|
341
259
|
function hasSyntaxOnlyCheckMode(root: string): boolean {
|
|
342
260
|
if (!isWorkflowContextName(root)) return resolveContextRootHost(root) === 'server';
|
|
343
261
|
return isWorkflowContextName(root) && getWorkflowContextDefinition(root).checkMode === 'syntax';
|
|
344
262
|
}
|
|
345
263
|
|
|
346
264
|
function mergeTypeEnvironments(
|
|
265
|
+
field: WorkflowPredicateField,
|
|
347
266
|
roots: readonly string[],
|
|
348
267
|
typeOverlay?: ExpressionTypeEnvironment,
|
|
349
268
|
): ExpressionTypeEnvironment {
|
|
@@ -351,28 +270,45 @@ function mergeTypeEnvironments(
|
|
|
351
270
|
|
|
352
271
|
for (const root of roots) {
|
|
353
272
|
const overlayType = typeOverlay?.[root];
|
|
354
|
-
if (overlayType !== undefined) {
|
|
355
|
-
typeEnvironment[root] = overlayType;
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
273
|
if (!isWorkflowContextName(root)) {
|
|
360
|
-
if (
|
|
274
|
+
if (overlayType !== undefined) typeEnvironment[root] = overlayType;
|
|
275
|
+
else typeEnvironment[root] = {kind: 'map'};
|
|
361
276
|
continue;
|
|
362
277
|
}
|
|
363
278
|
|
|
364
|
-
const contextTypeEnvironment =
|
|
279
|
+
const contextTypeEnvironment = getWorkflowPredicateFieldTypeEnvironment(field, root);
|
|
365
280
|
if (contextTypeEnvironment === undefined) {
|
|
366
|
-
if (
|
|
281
|
+
if (overlayType !== undefined) typeEnvironment[root] = overlayType;
|
|
282
|
+
else typeEnvironment[root] = {kind: 'map'};
|
|
367
283
|
continue;
|
|
368
284
|
}
|
|
369
285
|
|
|
370
|
-
|
|
286
|
+
const contextType = contextTypeEnvironment[root];
|
|
287
|
+
if (contextType === undefined) continue;
|
|
288
|
+
typeEnvironment[root] =
|
|
289
|
+
overlayType === undefined ? contextType : overlayKnownFields(contextType, overlayType);
|
|
371
290
|
}
|
|
372
291
|
|
|
373
292
|
return typeEnvironment;
|
|
374
293
|
}
|
|
375
294
|
|
|
295
|
+
function overlayKnownFields(base: ExpressionType, overlay: ExpressionType): ExpressionType {
|
|
296
|
+
if (typeof base === 'string' || typeof overlay === 'string') return overlay;
|
|
297
|
+
if (base.kind !== 'object' || overlay.kind !== 'object') return overlay;
|
|
298
|
+
|
|
299
|
+
// Preserve output specialization without reintroducing properties absent from this field's
|
|
300
|
+
// runtime shape.
|
|
301
|
+
return {
|
|
302
|
+
kind: 'object',
|
|
303
|
+
fields: Object.fromEntries(
|
|
304
|
+
Object.entries(base.fields).map(([key, fieldType]) => [
|
|
305
|
+
key,
|
|
306
|
+
overlay.fields[key] ?? fieldType,
|
|
307
|
+
]),
|
|
308
|
+
),
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
376
312
|
function isWorkflowContextName(root: string): root is WorkflowContextName {
|
|
377
313
|
return (workflowContextNames as readonly string[]).includes(root);
|
|
378
314
|
}
|
|
@@ -397,10 +333,6 @@ function describeAvailabilitySite(site: AvailabilitySite): string {
|
|
|
397
333
|
return availabilitySiteLabels[site];
|
|
398
334
|
}
|
|
399
335
|
|
|
400
|
-
function isSiteAtOrAfter(site: AvailabilitySite, fillTarget: AvailabilitySite): boolean {
|
|
401
|
-
return availabilitySites.indexOf(site) >= availabilitySites.indexOf(fillTarget);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
336
|
function formatList(values: readonly string[]): string {
|
|
405
337
|
return values.map((value) => `"${value}"`).join(', ');
|
|
406
338
|
}
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
WorkflowModelValidationIssue,
|
|
3
3
|
WorkflowModelValidationIssueCode,
|
|
4
4
|
WorkflowModelValidationIssuePathSegment,
|
|
5
|
+
WorkflowModelValidationIssueSeverity,
|
|
5
6
|
} from './invalid-workflow-model-error.js';
|
|
6
7
|
|
|
7
8
|
export function issue(params: {
|
|
@@ -9,12 +10,14 @@ export function issue(params: {
|
|
|
9
10
|
message: string;
|
|
10
11
|
path: readonly WorkflowModelValidationIssuePathSegment[];
|
|
11
12
|
details?: Readonly<Record<string, unknown>>;
|
|
13
|
+
severity?: WorkflowModelValidationIssueSeverity;
|
|
12
14
|
}): WorkflowModelValidationIssue {
|
|
13
15
|
if (params.details === undefined) {
|
|
14
16
|
return {
|
|
15
17
|
code: params.code,
|
|
16
18
|
message: params.message,
|
|
17
19
|
path: params.path,
|
|
20
|
+
...(params.severity === undefined ? {} : {severity: params.severity}),
|
|
18
21
|
};
|
|
19
22
|
}
|
|
20
23
|
|
|
@@ -23,5 +26,6 @@ export function issue(params: {
|
|
|
23
26
|
message: params.message,
|
|
24
27
|
path: params.path,
|
|
25
28
|
details: params.details,
|
|
29
|
+
...(params.severity === undefined ? {} : {severity: params.severity}),
|
|
26
30
|
};
|
|
27
31
|
}
|
|
@@ -20,10 +20,24 @@ export function workflowFieldLabel(
|
|
|
20
20
|
return 'Job runner interpolation';
|
|
21
21
|
case 'job.outputs':
|
|
22
22
|
return 'Job outputs mapping';
|
|
23
|
-
case '
|
|
24
|
-
return '
|
|
23
|
+
case 'workflow.run_name':
|
|
24
|
+
return 'Workflow run name interpolation';
|
|
25
|
+
case 'job.execution_name':
|
|
26
|
+
return 'Job execution name interpolation';
|
|
25
27
|
case 'step.name':
|
|
26
28
|
return 'Step name interpolation';
|
|
29
|
+
case 'step.working_directory':
|
|
30
|
+
return 'Step working directory interpolation';
|
|
31
|
+
case 'checkout.project':
|
|
32
|
+
return 'Checkout project interpolation';
|
|
33
|
+
case 'checkout.connection':
|
|
34
|
+
return 'Checkout connection interpolation';
|
|
35
|
+
case 'checkout.repository':
|
|
36
|
+
return 'Checkout repository interpolation';
|
|
37
|
+
case 'checkout.ref':
|
|
38
|
+
return 'Checkout ref interpolation';
|
|
39
|
+
case 'checkout.path':
|
|
40
|
+
return 'Checkout path interpolation';
|
|
27
41
|
case 'step.success':
|
|
28
42
|
return 'Step gate success';
|
|
29
43
|
case 'step.feedback':
|
|
@@ -29,7 +29,7 @@ to read and easy to change.
|
|
|
29
29
|
|
|
30
30
|
That keeps the next part clear too.
|
|
31
31
|
|
|
32
|
-
## Installation
|
|
32
|
+
## Installation and setup
|
|
33
33
|
|
|
34
34
|
This code is part of `@shipfox/api-definitions`. It is not a standalone package.
|
|
35
35
|
|
|
@@ -59,7 +59,7 @@ jobs:
|
|
|
59
59
|
console.log(document.jobs.build.steps[0]?.run);
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
## Behavior
|
|
62
|
+
## Behavior notes
|
|
63
63
|
|
|
64
64
|
The parser owns only YAML concerns. It does not set defaults. It does not change
|
|
65
65
|
job ids. It does not build job graphs. It does not check expressions.
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {uuidv7PrimaryKey} from '@shipfox/node-drizzle';
|
|
2
2
|
import {sql} from 'drizzle-orm';
|
|
3
|
-
import {index, pgEnum, text, timestamp, uniqueIndex, uuid} from 'drizzle-orm/pg-core';
|
|
3
|
+
import {index, jsonb, pgEnum, text, timestamp, uniqueIndex, uuid} from 'drizzle-orm/pg-core';
|
|
4
4
|
import type {
|
|
5
5
|
DefinitionSyncErrorCode,
|
|
6
6
|
DefinitionSyncState,
|
|
7
7
|
DefinitionSyncStatus,
|
|
8
|
+
DefinitionSyncWarning,
|
|
8
9
|
} from '#core/entities/sync-state.js';
|
|
9
10
|
import {pgTable} from './common.js';
|
|
10
11
|
|
|
@@ -42,6 +43,7 @@ export const definitionSyncStates = pgTable(
|
|
|
42
43
|
status: definitionSyncStatusEnum('status').notNull().default('pending'),
|
|
43
44
|
lastErrorCode: definitionSyncErrorCodeEnum('last_error_code'),
|
|
44
45
|
lastErrorMessage: text('last_error_message'),
|
|
46
|
+
warnings: jsonb('warnings').notNull().default([]).$type<DefinitionSyncWarning[]>(),
|
|
45
47
|
startedAt: timestamp('started_at', {withTimezone: true}),
|
|
46
48
|
finishedAt: timestamp('finished_at', {withTimezone: true}),
|
|
47
49
|
createdAt: timestamp('created_at', {withTimezone: true}).notNull().defaultNow(),
|
|
@@ -71,6 +73,7 @@ export function toDefinitionSyncState(row: DefinitionSyncStateDb): DefinitionSyn
|
|
|
71
73
|
status: row.status as DefinitionSyncStatus,
|
|
72
74
|
lastErrorCode: row.lastErrorCode as DefinitionSyncErrorCode | null,
|
|
73
75
|
lastErrorMessage: row.lastErrorMessage,
|
|
76
|
+
warnings: row.warnings ?? [],
|
|
74
77
|
startedAt: row.startedAt,
|
|
75
78
|
finishedAt: row.finishedAt,
|
|
76
79
|
createdAt: row.createdAt,
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFINITION_SYNC_WARNING_CODE_MAX_LENGTH,
|
|
3
|
+
DEFINITION_SYNC_WARNING_MESSAGE_MAX_LENGTH,
|
|
4
|
+
DEFINITION_SYNC_WARNING_PATH_MAX_LENGTH,
|
|
5
|
+
DEFINITION_SYNC_WARNINGS_MAX_COUNT,
|
|
6
|
+
} from '@shipfox/api-definitions-dto';
|
|
1
7
|
import {eq} from 'drizzle-orm';
|
|
2
8
|
import {db} from './db.js';
|
|
3
9
|
import {definitionSyncStates} from './schema/sync-states.js';
|
|
@@ -59,6 +65,57 @@ describe('definition sync state queries', () => {
|
|
|
59
65
|
expect(second.startedAt?.getTime()).toBe(first.startedAt?.getTime());
|
|
60
66
|
});
|
|
61
67
|
|
|
68
|
+
it('persists warnings and clears them on a subsequent sync', async () => {
|
|
69
|
+
const warnings = [
|
|
70
|
+
{
|
|
71
|
+
code: 're-evaluating-command',
|
|
72
|
+
message: 'Workflow data is re-executed as shell code.',
|
|
73
|
+
path: 'jobs.build.steps.0.run',
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
const succeeded = await markDefinitionSyncState({
|
|
78
|
+
projectId,
|
|
79
|
+
sourceConnectionId,
|
|
80
|
+
sourceExternalRepositoryId: 'gitea-owner/platform',
|
|
81
|
+
ref: 'main',
|
|
82
|
+
status: 'succeeded',
|
|
83
|
+
warnings,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
expect(succeeded.warnings).toEqual(warnings);
|
|
87
|
+
|
|
88
|
+
const syncing = await markDefinitionSyncState({
|
|
89
|
+
projectId,
|
|
90
|
+
sourceConnectionId,
|
|
91
|
+
sourceExternalRepositoryId: 'gitea-owner/platform',
|
|
92
|
+
ref: 'main',
|
|
93
|
+
status: 'syncing',
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(syncing.warnings).toEqual([]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('bounds warning payloads before persisting them', async () => {
|
|
100
|
+
const state = await markDefinitionSyncState({
|
|
101
|
+
projectId,
|
|
102
|
+
sourceConnectionId,
|
|
103
|
+
sourceExternalRepositoryId: 'gitea-owner/platform',
|
|
104
|
+
ref: 'main',
|
|
105
|
+
status: 'succeeded',
|
|
106
|
+
warnings: Array.from({length: DEFINITION_SYNC_WARNINGS_MAX_COUNT + 1}, (_, index) => ({
|
|
107
|
+
code: `${index}-${'c'.repeat(DEFINITION_SYNC_WARNING_CODE_MAX_LENGTH)}`,
|
|
108
|
+
message: `${index}-${'m'.repeat(DEFINITION_SYNC_WARNING_MESSAGE_MAX_LENGTH)}`,
|
|
109
|
+
path: `${index}-${'p'.repeat(DEFINITION_SYNC_WARNING_PATH_MAX_LENGTH)}`,
|
|
110
|
+
})),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
expect(state.warnings).toHaveLength(DEFINITION_SYNC_WARNINGS_MAX_COUNT);
|
|
114
|
+
expect(state.warnings[0]?.code).toHaveLength(DEFINITION_SYNC_WARNING_CODE_MAX_LENGTH);
|
|
115
|
+
expect(state.warnings[0]?.message).toHaveLength(DEFINITION_SYNC_WARNING_MESSAGE_MAX_LENGTH);
|
|
116
|
+
expect(state.warnings[0]?.path).toHaveLength(DEFINITION_SYNC_WARNING_PATH_MAX_LENGTH);
|
|
117
|
+
});
|
|
118
|
+
|
|
62
119
|
it('clears stale finish data when a sync starts again', async () => {
|
|
63
120
|
await markDefinitionSyncState({
|
|
64
121
|
projectId,
|
package/src/db/sync-states.ts
CHANGED
|
@@ -3,7 +3,9 @@ import type {
|
|
|
3
3
|
DefinitionSyncErrorCode,
|
|
4
4
|
DefinitionSyncState,
|
|
5
5
|
DefinitionSyncStatus,
|
|
6
|
+
DefinitionSyncWarning,
|
|
6
7
|
} from '#core/entities/sync-state.js';
|
|
8
|
+
import {limitDefinitionSyncWarnings} from '#core/entities/sync-state.js';
|
|
7
9
|
import {db} from './db.js';
|
|
8
10
|
import {definitionSyncStates, toDefinitionSyncState} from './schema/sync-states.js';
|
|
9
11
|
|
|
@@ -18,6 +20,7 @@ export interface MarkDefinitionSyncParams extends DefinitionSyncStateKey {
|
|
|
18
20
|
status: DefinitionSyncStatus;
|
|
19
21
|
lastErrorCode?: DefinitionSyncErrorCode | null | undefined;
|
|
20
22
|
lastErrorMessage?: string | null | undefined;
|
|
23
|
+
warnings?: readonly DefinitionSyncWarning[] | null | undefined;
|
|
21
24
|
startedAt?: Date | null | undefined;
|
|
22
25
|
finishedAt?: Date | null | undefined;
|
|
23
26
|
}
|
|
@@ -26,6 +29,7 @@ export async function markDefinitionSyncState(
|
|
|
26
29
|
params: MarkDefinitionSyncParams,
|
|
27
30
|
): Promise<DefinitionSyncState> {
|
|
28
31
|
const now = new Date();
|
|
32
|
+
const warnings = limitDefinitionSyncWarnings(params.warnings ?? []);
|
|
29
33
|
const [row] = await db()
|
|
30
34
|
.insert(definitionSyncStates)
|
|
31
35
|
.values({
|
|
@@ -36,6 +40,7 @@ export async function markDefinitionSyncState(
|
|
|
36
40
|
status: params.status,
|
|
37
41
|
lastErrorCode: params.lastErrorCode ?? null,
|
|
38
42
|
lastErrorMessage: params.lastErrorMessage ?? null,
|
|
43
|
+
warnings,
|
|
39
44
|
startedAt: params.startedAt ?? null,
|
|
40
45
|
finishedAt: params.finishedAt ?? null,
|
|
41
46
|
updatedAt: now,
|
|
@@ -51,6 +56,7 @@ export async function markDefinitionSyncState(
|
|
|
51
56
|
status: params.status,
|
|
52
57
|
lastErrorCode: params.lastErrorCode ?? null,
|
|
53
58
|
lastErrorMessage: params.lastErrorMessage ?? null,
|
|
59
|
+
warnings,
|
|
54
60
|
...(params.startedAt !== undefined ? {startedAt: params.startedAt} : {}),
|
|
55
61
|
...(params.finishedAt !== undefined ? {finishedAt: params.finishedAt} : {}),
|
|
56
62
|
updatedAt: now,
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,10 @@ import {
|
|
|
6
6
|
type DefinitionsEventMap,
|
|
7
7
|
definitionsEventSchemas,
|
|
8
8
|
} from '@shipfox/api-definitions-dto';
|
|
9
|
+
import {
|
|
10
|
+
INTEGRATION_CONNECTION_AVAILABLE,
|
|
11
|
+
type IntegrationsEventMap,
|
|
12
|
+
} from '@shipfox/api-integration-core-dto';
|
|
9
13
|
import type {IntegrationsModuleClient} from '@shipfox/api-integration-core-dto/inter-module';
|
|
10
14
|
import {
|
|
11
15
|
PROJECT_SOURCE_BOUND,
|
|
@@ -20,6 +24,7 @@ import {db, definitionsOutbox, migrationsPath} from '#db/index.js';
|
|
|
20
24
|
import {createDefinitionRoutes} from '#presentation/index.js';
|
|
21
25
|
import {createDefinitionsInterModulePresentation} from '#presentation/inter-module.js';
|
|
22
26
|
import {
|
|
27
|
+
createOnIntegrationConnectionAvailable,
|
|
23
28
|
onProjectSourceBound,
|
|
24
29
|
onProjectSourceCommitObserved,
|
|
25
30
|
} from '#presentation/subscribers/index.js';
|
|
@@ -46,7 +51,9 @@ export {db, definitionsOutbox, getDefinitionById, migrationsPath} from '#db/inde
|
|
|
46
51
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
47
52
|
const workflowsPath = resolve(packageRoot, 'dist/temporal/workflows/index.js');
|
|
48
53
|
|
|
49
|
-
const subscriber = subscriberFactory<
|
|
54
|
+
const subscriber = subscriberFactory<
|
|
55
|
+
DefinitionsEventMap & IntegrationsEventMap & ProjectsEventMap
|
|
56
|
+
>();
|
|
50
57
|
|
|
51
58
|
export interface CreateDefinitionsModuleOptions {
|
|
52
59
|
projects: ProjectsModuleClient;
|
|
@@ -73,6 +80,10 @@ export function createDefinitionsModule({
|
|
|
73
80
|
logger().info({event}, 'Definition resolved');
|
|
74
81
|
return Promise.resolve();
|
|
75
82
|
}),
|
|
83
|
+
subscriber(
|
|
84
|
+
INTEGRATION_CONNECTION_AVAILABLE,
|
|
85
|
+
createOnIntegrationConnectionAvailable(projects),
|
|
86
|
+
),
|
|
76
87
|
subscriber(PROJECT_SOURCE_BOUND, onProjectSourceBound),
|
|
77
88
|
subscriber(PROJECT_SOURCE_COMMIT_OBSERVED, onProjectSourceCommitObserved),
|
|
78
89
|
],
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type {AgentInterModuleClient} from '@shipfox/api-agent-dto/inter-module';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
definitionDtoSchema,
|
|
4
|
+
definitionValidationErrorSchema,
|
|
5
|
+
definitionValidationWarningSchema,
|
|
6
|
+
} from '@shipfox/api-definitions-dto';
|
|
3
7
|
import {defineRoute} from '@shipfox/node-fastify';
|
|
4
8
|
import {z} from 'zod';
|
|
5
9
|
import {validateDefinition} from '#core/validate-definition.js';
|
|
@@ -13,6 +17,7 @@ const validationResultSchema = z.union([
|
|
|
13
17
|
valid: z.literal(true),
|
|
14
18
|
workflow_document: definitionDtoSchema.shape.workflow_document,
|
|
15
19
|
workflow_model: definitionDtoSchema.shape.workflow_model,
|
|
20
|
+
warnings: z.array(definitionValidationWarningSchema),
|
|
16
21
|
}),
|
|
17
22
|
z.object({
|
|
18
23
|
valid: z.literal(false),
|
|
@@ -42,6 +47,7 @@ export function buildValidateDefinitionRoute(agent: AgentInterModuleClient) {
|
|
|
42
47
|
valid: true as const,
|
|
43
48
|
workflow_document: result.definition.document,
|
|
44
49
|
workflow_model: result.definition.model,
|
|
50
|
+
warnings: result.warnings,
|
|
45
51
|
};
|
|
46
52
|
}
|
|
47
53
|
|