@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
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type {IntegrationConnectionAvailableEvent} from '@shipfox/api-integration-core-dto';
|
|
2
|
+
import type {DomainEvent} from '@shipfox/node-outbox';
|
|
3
|
+
import {createOnIntegrationConnectionAvailable} from './on-integration-connection-available.js';
|
|
4
|
+
|
|
5
|
+
const startMock = vi.fn();
|
|
6
|
+
|
|
7
|
+
vi.mock('@shipfox/node-temporal', () => ({
|
|
8
|
+
temporalClient: () => ({workflow: {start: startMock}}),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
function project(name: string, workspaceId: string) {
|
|
12
|
+
return {
|
|
13
|
+
id: crypto.randomUUID(),
|
|
14
|
+
workspaceId,
|
|
15
|
+
sourceConnectionId: crypto.randomUUID(),
|
|
16
|
+
sourceExternalRepositoryId: `github:${name}`,
|
|
17
|
+
sourceRepositoryOwner: 'shipfox',
|
|
18
|
+
name,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe('onIntegrationConnectionAvailable', () => {
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
startMock.mockReset();
|
|
25
|
+
startMock.mockResolvedValue({});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('paginates workspace projects and starts an event-keyed sync for each one', async () => {
|
|
29
|
+
const workspaceId = crypto.randomUUID();
|
|
30
|
+
const first = project('first', workspaceId);
|
|
31
|
+
const second = project('second', workspaceId);
|
|
32
|
+
const cursor = {createdAt: '2026-08-05T12:00:00.000Z', id: first.id};
|
|
33
|
+
const listProjectsByWorkspace = vi
|
|
34
|
+
.fn()
|
|
35
|
+
.mockResolvedValueOnce({projects: [first], nextCursor: cursor})
|
|
36
|
+
.mockResolvedValueOnce({projects: [second], nextCursor: null});
|
|
37
|
+
const handler = createOnIntegrationConnectionAvailable({listProjectsByWorkspace} as never);
|
|
38
|
+
const payload: IntegrationConnectionAvailableEvent = {
|
|
39
|
+
provider: 'linear',
|
|
40
|
+
workspaceId: first.workspaceId,
|
|
41
|
+
connectionId: crypto.randomUUID(),
|
|
42
|
+
slug: 'linear_shipfox',
|
|
43
|
+
};
|
|
44
|
+
const event: DomainEvent<IntegrationConnectionAvailableEvent> = {
|
|
45
|
+
id: crypto.randomUUID(),
|
|
46
|
+
type: 'integrations.connection.available',
|
|
47
|
+
payload,
|
|
48
|
+
createdAt: new Date(),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
await handler(payload, event);
|
|
52
|
+
|
|
53
|
+
expect(listProjectsByWorkspace).toHaveBeenNthCalledWith(1, {
|
|
54
|
+
workspaceId: payload.workspaceId,
|
|
55
|
+
limit: 100,
|
|
56
|
+
});
|
|
57
|
+
expect(listProjectsByWorkspace).toHaveBeenNthCalledWith(2, {
|
|
58
|
+
workspaceId: payload.workspaceId,
|
|
59
|
+
limit: 100,
|
|
60
|
+
cursor,
|
|
61
|
+
});
|
|
62
|
+
expect(startMock).toHaveBeenCalledTimes(2);
|
|
63
|
+
for (const candidate of [first, second]) {
|
|
64
|
+
expect(startMock).toHaveBeenCalledWith('definitionSyncWorkflow', {
|
|
65
|
+
taskQueue: 'definitions-sync',
|
|
66
|
+
workflowId: `definition-sync:${candidate.id}:integration:${event.id}`,
|
|
67
|
+
workflowIdConflictPolicy: 'USE_EXISTING',
|
|
68
|
+
workflowIdReusePolicy: 'REJECT_DUPLICATE',
|
|
69
|
+
args: [
|
|
70
|
+
{
|
|
71
|
+
projectId: candidate.id,
|
|
72
|
+
workspaceId: candidate.workspaceId,
|
|
73
|
+
sourceConnectionId: candidate.sourceConnectionId,
|
|
74
|
+
sourceExternalRepositoryId: candidate.sourceExternalRepositoryId,
|
|
75
|
+
sourceRef: undefined,
|
|
76
|
+
sourceCommitSha: undefined,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('treats an already-started event-keyed sync as successfully delivered', async () => {
|
|
84
|
+
const workspaceId = crypto.randomUUID();
|
|
85
|
+
const candidate = project('first', workspaceId);
|
|
86
|
+
const alreadyStarted = new Error('Workflow execution already started');
|
|
87
|
+
alreadyStarted.name = 'WorkflowExecutionAlreadyStartedError';
|
|
88
|
+
startMock.mockRejectedValue(alreadyStarted);
|
|
89
|
+
const handler = createOnIntegrationConnectionAvailable({
|
|
90
|
+
listProjectsByWorkspace: vi.fn(() =>
|
|
91
|
+
Promise.resolve({projects: [candidate], nextCursor: null}),
|
|
92
|
+
),
|
|
93
|
+
} as never);
|
|
94
|
+
const payload: IntegrationConnectionAvailableEvent = {
|
|
95
|
+
provider: 'linear',
|
|
96
|
+
workspaceId,
|
|
97
|
+
connectionId: crypto.randomUUID(),
|
|
98
|
+
slug: 'linear_shipfox',
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
await expect(
|
|
102
|
+
handler(payload, {
|
|
103
|
+
id: crypto.randomUUID(),
|
|
104
|
+
type: 'integrations.connection.available',
|
|
105
|
+
payload,
|
|
106
|
+
createdAt: new Date(),
|
|
107
|
+
}),
|
|
108
|
+
).resolves.toBeUndefined();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('rethrows project lookup failures so the outbox event can retry', async () => {
|
|
112
|
+
const failure = new Error('projects unavailable');
|
|
113
|
+
const handler = createOnIntegrationConnectionAvailable({
|
|
114
|
+
listProjectsByWorkspace: vi.fn(() => Promise.reject(failure)),
|
|
115
|
+
} as never);
|
|
116
|
+
const payload: IntegrationConnectionAvailableEvent = {
|
|
117
|
+
provider: 'linear',
|
|
118
|
+
workspaceId: crypto.randomUUID(),
|
|
119
|
+
connectionId: crypto.randomUUID(),
|
|
120
|
+
slug: 'linear_shipfox',
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
await expect(
|
|
124
|
+
handler(payload, {
|
|
125
|
+
id: crypto.randomUUID(),
|
|
126
|
+
type: 'integrations.connection.available',
|
|
127
|
+
payload,
|
|
128
|
+
createdAt: new Date(),
|
|
129
|
+
}),
|
|
130
|
+
).rejects.toBe(failure);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type {IntegrationConnectionAvailableEvent} from '@shipfox/api-integration-core-dto';
|
|
2
|
+
import type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';
|
|
3
|
+
import {boundedMap} from '@shipfox/node-module';
|
|
4
|
+
import type {DomainEvent} from '@shipfox/node-outbox';
|
|
5
|
+
import {startDefinitionSync} from './start-definition-sync.js';
|
|
6
|
+
|
|
7
|
+
const PROJECT_PAGE_SIZE = 100;
|
|
8
|
+
const SYNC_START_CONCURRENCY = 10;
|
|
9
|
+
|
|
10
|
+
export function createOnIntegrationConnectionAvailable(
|
|
11
|
+
projects: Pick<ProjectsModuleClient, 'listProjectsByWorkspace'>,
|
|
12
|
+
) {
|
|
13
|
+
return async function onIntegrationConnectionAvailable(
|
|
14
|
+
payload: IntegrationConnectionAvailableEvent,
|
|
15
|
+
event: DomainEvent<IntegrationConnectionAvailableEvent>,
|
|
16
|
+
): Promise<void> {
|
|
17
|
+
let cursor: {createdAt: string; id: string} | undefined;
|
|
18
|
+
|
|
19
|
+
do {
|
|
20
|
+
const page = await projects.listProjectsByWorkspace({
|
|
21
|
+
workspaceId: payload.workspaceId,
|
|
22
|
+
limit: PROJECT_PAGE_SIZE,
|
|
23
|
+
...(cursor ? {cursor} : {}),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
await boundedMap(
|
|
27
|
+
page.projects,
|
|
28
|
+
SYNC_START_CONCURRENCY,
|
|
29
|
+
async (project) => {
|
|
30
|
+
await startDefinitionSync({
|
|
31
|
+
projectId: project.id,
|
|
32
|
+
workspaceId: project.workspaceId,
|
|
33
|
+
sourceConnectionId: project.sourceConnectionId,
|
|
34
|
+
externalRepositoryId: project.sourceExternalRepositoryId,
|
|
35
|
+
requestId: `integration:${event.id}`,
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
{stopOnError: true},
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
cursor = page.nextCursor ?? undefined;
|
|
42
|
+
} while (cursor);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -8,31 +8,47 @@ export interface StartDefinitionSyncParams {
|
|
|
8
8
|
externalRepositoryId: string;
|
|
9
9
|
sourceRef?: string | undefined;
|
|
10
10
|
sourceCommitSha?: string | undefined;
|
|
11
|
+
requestId?: string | undefined;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export async function startDefinitionSync(params: StartDefinitionSyncParams): Promise<void> {
|
|
14
15
|
const workflowId = buildWorkflowId(params);
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
17
|
+
try {
|
|
18
|
+
await temporalClient().workflow.start(DEFINITION_SYNC_WORKFLOW, {
|
|
19
|
+
taskQueue: DEFINITIONS_TASK_QUEUE,
|
|
20
|
+
workflowId,
|
|
21
|
+
workflowIdConflictPolicy: 'USE_EXISTING',
|
|
22
|
+
workflowIdReusePolicy: params.requestId ? 'REJECT_DUPLICATE' : 'ALLOW_DUPLICATE',
|
|
23
|
+
args: [
|
|
24
|
+
{
|
|
25
|
+
projectId: params.projectId,
|
|
26
|
+
workspaceId: params.workspaceId,
|
|
27
|
+
sourceConnectionId: params.sourceConnectionId,
|
|
28
|
+
sourceExternalRepositoryId: params.externalRepositoryId,
|
|
29
|
+
sourceRef: params.sourceRef,
|
|
30
|
+
sourceCommitSha: params.sourceCommitSha,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
} catch (error) {
|
|
35
|
+
if (
|
|
36
|
+
params.requestId &&
|
|
37
|
+
error instanceof Error &&
|
|
38
|
+
error.name === 'WorkflowExecutionAlreadyStartedError'
|
|
39
|
+
) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
32
44
|
}
|
|
33
45
|
|
|
34
46
|
function buildWorkflowId(params: StartDefinitionSyncParams): string {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
47
|
+
if (params.sourceCommitSha) {
|
|
48
|
+
return `definition-sync:${params.projectId}:${params.sourceCommitSha}`;
|
|
49
|
+
}
|
|
50
|
+
if (params.requestId) {
|
|
51
|
+
return `definition-sync:${params.projectId}:${params.requestId}`;
|
|
52
|
+
}
|
|
53
|
+
return `definition-sync:${params.projectId}:bind`;
|
|
38
54
|
}
|
|
@@ -224,6 +224,7 @@ describe('definition sync activities', () => {
|
|
|
224
224
|
|
|
225
225
|
expect(result.appliedCount).toBe(1);
|
|
226
226
|
expect(result.deletedCount).toBe(0);
|
|
227
|
+
expect(result.warnings).toEqual([]);
|
|
227
228
|
});
|
|
228
229
|
|
|
229
230
|
it('translates DefinitionSyncPermanentError into a non-retryable ApplicationFailure', async () => {
|
|
@@ -308,6 +309,7 @@ describe('definition sync activities', () => {
|
|
|
308
309
|
expect(rows[0]?.status).toBe('failed');
|
|
309
310
|
expect(rows[0]?.lastErrorCode).toBe('invalid-definition');
|
|
310
311
|
expect(rows[0]?.lastErrorMessage).toBe('Invalid workflow at .shipfox/workflows/bad.yml');
|
|
312
|
+
expect(rows[0]?.warnings).toEqual([]);
|
|
311
313
|
expect(rows[0]?.finishedAt).not.toBeNull();
|
|
312
314
|
});
|
|
313
315
|
|
|
@@ -362,6 +364,13 @@ describe('definition sync activities', () => {
|
|
|
362
364
|
sourceConnectionId,
|
|
363
365
|
sourceExternalRepositoryId: 'gitea:gitea-owner/platform',
|
|
364
366
|
sourceRef: 'main',
|
|
367
|
+
warnings: [
|
|
368
|
+
{
|
|
369
|
+
code: 're-evaluating-command',
|
|
370
|
+
message: 'Workflow data is re-executed as shell code.',
|
|
371
|
+
path: 'jobs.build.steps.0.run',
|
|
372
|
+
},
|
|
373
|
+
],
|
|
365
374
|
});
|
|
366
375
|
await result;
|
|
367
376
|
|
|
@@ -372,6 +381,13 @@ describe('definition sync activities', () => {
|
|
|
372
381
|
expect(rows[0]?.status).toBe('succeeded');
|
|
373
382
|
expect(rows[0]?.lastErrorCode).toBeNull();
|
|
374
383
|
expect(rows[0]?.lastErrorMessage).toBeNull();
|
|
384
|
+
expect(rows[0]?.warnings).toEqual([
|
|
385
|
+
{
|
|
386
|
+
code: 're-evaluating-command',
|
|
387
|
+
message: 'Workflow data is re-executed as shell code.',
|
|
388
|
+
path: 'jobs.build.steps.0.run',
|
|
389
|
+
},
|
|
390
|
+
]);
|
|
375
391
|
});
|
|
376
392
|
});
|
|
377
393
|
});
|
|
@@ -3,7 +3,7 @@ import type {IntegrationsModuleClient} from '@shipfox/api-integration-core-dto/i
|
|
|
3
3
|
import {markErrorReported} from '@shipfox/node-error-monitoring';
|
|
4
4
|
import {Context} from '@temporalio/activity';
|
|
5
5
|
import {ApplicationFailure} from '@temporalio/common';
|
|
6
|
-
import type {DefinitionSyncErrorCode} from '#core/entities/sync-state.js';
|
|
6
|
+
import type {DefinitionSyncErrorCode, DefinitionSyncWarning} from '#core/entities/sync-state.js';
|
|
7
7
|
import {
|
|
8
8
|
classifySyncFailure,
|
|
9
9
|
discoverWorkflowFiles,
|
|
@@ -50,6 +50,11 @@ export interface DiscoverWorkflowsActivityResult {
|
|
|
50
50
|
export interface FetchAndApplyActivityResult {
|
|
51
51
|
appliedCount: number;
|
|
52
52
|
deletedCount: number;
|
|
53
|
+
warnings: DefinitionSyncWarning[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface MarkSyncSucceededActivityInput extends SyncRefScopedInput {
|
|
57
|
+
warnings?: readonly DefinitionSyncWarning[] | undefined;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
export interface DefinitionSyncActivityOptions {
|
|
@@ -93,6 +98,7 @@ function createPrepareDefinitionSyncActivity(sourceControl: DefinitionsSourceCon
|
|
|
93
98
|
status: 'syncing',
|
|
94
99
|
lastErrorCode: null,
|
|
95
100
|
lastErrorMessage: null,
|
|
101
|
+
warnings: [],
|
|
96
102
|
startedAt: new Date(),
|
|
97
103
|
finishedAt: null,
|
|
98
104
|
});
|
|
@@ -147,7 +153,7 @@ function createFetchAndApplyActivity(
|
|
|
147
153
|
},
|
|
148
154
|
});
|
|
149
155
|
|
|
150
|
-
|
|
156
|
+
const result = await applyVcsDefinitionsBatch({
|
|
151
157
|
projectId: input.projectId,
|
|
152
158
|
workspaceId: input.workspaceId,
|
|
153
159
|
ref: input.sourceRef,
|
|
@@ -160,12 +166,19 @@ function createFetchAndApplyActivity(
|
|
|
160
166
|
contentHash: entry.contentHash,
|
|
161
167
|
})),
|
|
162
168
|
});
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
...result,
|
|
172
|
+
warnings: definitions.flatMap((entry) => entry.warnings),
|
|
173
|
+
};
|
|
163
174
|
});
|
|
164
175
|
};
|
|
165
176
|
}
|
|
166
177
|
|
|
167
178
|
function createMarkSyncSucceededActivity() {
|
|
168
|
-
return async function markDefinitionSyncSucceeded(
|
|
179
|
+
return async function markDefinitionSyncSucceeded(
|
|
180
|
+
input: MarkSyncSucceededActivityInput,
|
|
181
|
+
): Promise<void> {
|
|
169
182
|
await markDefinitionSyncState({
|
|
170
183
|
projectId: input.projectId,
|
|
171
184
|
sourceConnectionId: input.sourceConnectionId,
|
|
@@ -174,6 +187,7 @@ function createMarkSyncSucceededActivity() {
|
|
|
174
187
|
status: 'succeeded',
|
|
175
188
|
lastErrorCode: null,
|
|
176
189
|
lastErrorMessage: null,
|
|
190
|
+
warnings: input.warnings ?? [],
|
|
177
191
|
finishedAt: new Date(),
|
|
178
192
|
});
|
|
179
193
|
};
|
|
@@ -191,6 +205,7 @@ function createMarkSyncFailedActivity() {
|
|
|
191
205
|
status: 'failed',
|
|
192
206
|
lastErrorCode: input.code,
|
|
193
207
|
lastErrorMessage: input.message,
|
|
208
|
+
warnings: [],
|
|
194
209
|
finishedAt: new Date(),
|
|
195
210
|
});
|
|
196
211
|
};
|
|
@@ -65,7 +65,7 @@ export async function definitionSyncWorkflow(
|
|
|
65
65
|
const {paths} = await discoverDefinitionWorkflows(source);
|
|
66
66
|
const applied = await fetchAndApplyDefinitionWorkflows({...source, paths});
|
|
67
67
|
|
|
68
|
-
await markDefinitionSyncSucceeded(source);
|
|
68
|
+
await markDefinitionSyncSucceeded({...source, warnings: applied.warnings});
|
|
69
69
|
|
|
70
70
|
return {
|
|
71
71
|
sourceRef,
|
|
@@ -7,6 +7,21 @@ import {
|
|
|
7
7
|
} from '@shipfox/api-agent-dto';
|
|
8
8
|
import type {AgentValidationCatalog} from '@shipfox/api-agent-dto/inter-module';
|
|
9
9
|
|
|
10
|
+
const piModelIdsByProvider = Object.fromEntries(
|
|
11
|
+
MODEL_PROVIDER_CATALOG_SEED.filter((entry) => entry.support_status === 'supported').map(
|
|
12
|
+
(entry) => [
|
|
13
|
+
entry.id,
|
|
14
|
+
entry.id === 'anthropic'
|
|
15
|
+
? ['claude-opus-4-8']
|
|
16
|
+
: entry.id === 'openai'
|
|
17
|
+
? ['gpt-4.1', 'gpt-5.5-pro']
|
|
18
|
+
: entry.default_model === null
|
|
19
|
+
? []
|
|
20
|
+
: [entry.default_model],
|
|
21
|
+
],
|
|
22
|
+
),
|
|
23
|
+
);
|
|
24
|
+
|
|
10
25
|
export const agentValidationCatalog: AgentValidationCatalog = {
|
|
11
26
|
version: 1,
|
|
12
27
|
providers: MODEL_PROVIDER_IDS.map((id) => ({
|
|
@@ -17,6 +32,8 @@ export const agentValidationCatalog: AgentValidationCatalog = {
|
|
|
17
32
|
harnesses: listHarnessDescriptors().map((harness) => ({
|
|
18
33
|
id: harness.id,
|
|
19
34
|
supported_provider_ids: [...harness.supportedProviderIds],
|
|
35
|
+
model_ids_by_provider:
|
|
36
|
+
harness.id === 'pi' ? piModelIdsByProvider : {anthropic: ['claude-opus-4-8']},
|
|
20
37
|
thinking_levels: [...harness.thinkingLevels],
|
|
21
38
|
effective_tools: listEnabledHarnessTools(
|
|
22
39
|
harness.id,
|