@shipfox/api-definitions 9.0.2 → 9.1.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 +4 -4
- package/CHANGELOG.md +17 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/sync-definitions.d.ts +2 -1
- package/dist/core/sync-definitions.d.ts.map +1 -1
- package/dist/core/sync-definitions.js +4 -3
- package/dist/core/sync-definitions.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/temporal/activities/sync-activities.d.ts +4 -1
- package/dist/temporal/activities/sync-activities.d.ts.map +1 -1
- package/dist/temporal/activities/sync-activities.js +5 -4
- package/dist/temporal/activities/sync-activities.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/src/config.ts +6 -0
- package/src/core/index.ts +1 -1
- package/src/core/sync-definitions.test.ts +36 -0
- package/src/core/sync-definitions.ts +5 -3
- package/src/index.ts +5 -1
- package/src/temporal/activities/sync-activities.test.ts +29 -0
- package/src/temporal/activities/sync-activities.ts +14 -2
- package/tsconfig.build.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipfox/api-definitions",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "9.0
|
|
4
|
+
"version": "9.1.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/ShipfoxHQ/shipfox.git",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"yaml": "^2.8.3",
|
|
28
28
|
"zod": "^4.4.3",
|
|
29
29
|
"@shipfox/api-agent-dto": "9.0.2",
|
|
30
|
-
"@shipfox/api-auth-context": "9.0.
|
|
30
|
+
"@shipfox/api-auth-context": "9.0.3",
|
|
31
31
|
"@shipfox/api-definitions-dto": "9.0.2",
|
|
32
32
|
"@shipfox/api-integration-core-dto": "9.0.2",
|
|
33
33
|
"@shipfox/api-projects-dto": "9.0.2",
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
"@shipfox/expression": "1.1.5",
|
|
37
37
|
"@shipfox/inter-module": "0.2.2",
|
|
38
38
|
"@shipfox/node-drizzle": "0.3.4",
|
|
39
|
-
"@shipfox/node-fastify": "0.3.
|
|
40
|
-
"@shipfox/node-error-monitoring": "0.
|
|
41
|
-
"@shipfox/node-module": "1.0.
|
|
39
|
+
"@shipfox/node-fastify": "0.3.3",
|
|
40
|
+
"@shipfox/node-error-monitoring": "0.3.0",
|
|
41
|
+
"@shipfox/node-module": "1.0.2",
|
|
42
42
|
"@shipfox/node-opentelemetry": "0.6.2",
|
|
43
43
|
"@shipfox/node-outbox": "0.2.6",
|
|
44
44
|
"@shipfox/node-postgres": "0.4.4",
|
|
45
|
-
"@shipfox/node-temporal": "0.4.
|
|
45
|
+
"@shipfox/node-temporal": "0.4.3",
|
|
46
46
|
"@shipfox/runner-labels": "0.1.3",
|
|
47
47
|
"@shipfox/workflow-document": "2.1.3"
|
|
48
48
|
},
|
package/src/config.ts
CHANGED
|
@@ -6,6 +6,10 @@ export const config = createConfig({
|
|
|
6
6
|
desc: 'Default runner label(s) applied to workflow jobs that do not declare a "runner" at the job or workflow level. Set it to a comma-separated list, for example ubuntu-latest or ubuntu-latest,node-22. Leave it empty to require every workflow job to declare runner labels explicitly; with no value set, a job without a runner fails definition validation.',
|
|
7
7
|
default: '',
|
|
8
8
|
}),
|
|
9
|
+
DEFINITION_WORKFLOW_PATH: str({
|
|
10
|
+
desc: 'Repository-relative path that contains workflow YAML files. Set a different path for each Shipfox instance when staging and production share a repository.',
|
|
11
|
+
default: '.shipfox/workflows/',
|
|
12
|
+
}),
|
|
9
13
|
});
|
|
10
14
|
|
|
11
15
|
export function parseDefinitionDefaultRunnerLabels(value: string): readonly string[] {
|
|
@@ -30,3 +34,5 @@ export function parseDefinitionDefaultRunnerLabels(value: string): readonly stri
|
|
|
30
34
|
export const definitionDefaultRunnerLabels = parseDefinitionDefaultRunnerLabels(
|
|
31
35
|
config.DEFINITION_DEFAULT_RUNNER_LABEL,
|
|
32
36
|
);
|
|
37
|
+
|
|
38
|
+
export const definitionWorkflowPath = config.DEFINITION_WORKFLOW_PATH;
|
package/src/core/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ export {
|
|
|
6
6
|
export {parseDefinition} from './parse-definition.js';
|
|
7
7
|
export {
|
|
8
8
|
classifySyncFailure,
|
|
9
|
+
DEFAULT_WORKFLOW_PATH,
|
|
9
10
|
type DiscoverWorkflowFilesParams,
|
|
10
11
|
discoverWorkflowFiles,
|
|
11
12
|
type FetchAndParseWorkflowsParams,
|
|
@@ -18,7 +19,6 @@ export {
|
|
|
18
19
|
type SyncFailureClassification,
|
|
19
20
|
type SyncSourceContext,
|
|
20
21
|
UNRESOLVED_SYNC_REF,
|
|
21
|
-
WORKFLOW_PREFIX,
|
|
22
22
|
} from './sync-definitions.js';
|
|
23
23
|
export {DEFAULT_RUN_TIMEOUT_MS} from './workflow-model/constants.js';
|
|
24
24
|
export {normalizeWorkflowDocument} from './workflow-model/index.js';
|
|
@@ -146,6 +146,27 @@ describe('discoverWorkflowFiles', () => {
|
|
|
146
146
|
expect(result.paths).toEqual(['.shipfox/workflows/ci.yml', '.shipfox/workflows/deploy.yaml']);
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
+
it('lists workflows under the configured repository path', async () => {
|
|
150
|
+
const listFiles = vi.fn(() =>
|
|
151
|
+
Promise.resolve({
|
|
152
|
+
files: [{path: '.shipfox/staging/workflows/ci.yml', type: 'file' as const, size: 64}],
|
|
153
|
+
nextCursor: null,
|
|
154
|
+
}),
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const result = await discoverWorkflowFiles({
|
|
158
|
+
...baseContext,
|
|
159
|
+
ref: 'main',
|
|
160
|
+
workflowPath: '.shipfox/staging/workflows/',
|
|
161
|
+
sourceControl: sourceControl({listFiles}),
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
expect(listFiles).toHaveBeenCalledWith(
|
|
165
|
+
expect.objectContaining({prefix: '.shipfox/staging/workflows/'}),
|
|
166
|
+
);
|
|
167
|
+
expect(result.paths).toEqual(['.shipfox/staging/workflows/ci.yml']);
|
|
168
|
+
});
|
|
169
|
+
|
|
149
170
|
it('throws no-workflow-files when nothing matches the yaml extensions', async () => {
|
|
150
171
|
const result = discoverWorkflowFiles({
|
|
151
172
|
...baseContext,
|
|
@@ -163,6 +184,21 @@ describe('discoverWorkflowFiles', () => {
|
|
|
163
184
|
await expect(result).rejects.toMatchObject({code: 'no-workflow-files'});
|
|
164
185
|
});
|
|
165
186
|
|
|
187
|
+
it('includes the configured repository path when no workflow files are found', async () => {
|
|
188
|
+
const result = discoverWorkflowFiles({
|
|
189
|
+
...baseContext,
|
|
190
|
+
ref: 'main',
|
|
191
|
+
workflowPath: '.shipfox/production/workflows/',
|
|
192
|
+
sourceControl: sourceControl({
|
|
193
|
+
listFiles: vi.fn(() => Promise.resolve({files: [], nextCursor: null})),
|
|
194
|
+
}),
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
await expect(result).rejects.toThrow(
|
|
198
|
+
'No workflow files were found under .shipfox/production/workflows/',
|
|
199
|
+
);
|
|
200
|
+
});
|
|
201
|
+
|
|
166
202
|
it('throws too-many-files when the listing reports more pages', async () => {
|
|
167
203
|
const result = discoverWorkflowFiles({
|
|
168
204
|
...baseContext,
|
|
@@ -11,7 +11,7 @@ import {hasAgentStepIntegrations} from './has-agent-step-integrations.js';
|
|
|
11
11
|
import type {DefinitionsSourceControl} from './integrations.js';
|
|
12
12
|
import {parseDefinition} from './parse-definition.js';
|
|
13
13
|
|
|
14
|
-
export const
|
|
14
|
+
export const DEFAULT_WORKFLOW_PATH = '.shipfox/workflows/';
|
|
15
15
|
export const MAX_WORKFLOW_FILES = 100;
|
|
16
16
|
export const MAX_WORKFLOW_FILE_BYTES = 1_000_000;
|
|
17
17
|
export const FILE_FETCH_CONCURRENCY = 4;
|
|
@@ -39,17 +39,19 @@ export async function resolveSyncSource(params: SyncSourceContext): Promise<Reso
|
|
|
39
39
|
|
|
40
40
|
export interface DiscoverWorkflowFilesParams extends SyncSourceContext {
|
|
41
41
|
ref: string;
|
|
42
|
+
workflowPath?: string | undefined;
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
export async function discoverWorkflowFiles(
|
|
45
46
|
params: DiscoverWorkflowFilesParams,
|
|
46
47
|
): Promise<{paths: string[]}> {
|
|
48
|
+
const workflowPath = params.workflowPath ?? DEFAULT_WORKFLOW_PATH;
|
|
47
49
|
const page = await params.sourceControl.listFiles({
|
|
48
50
|
workspaceId: params.workspaceId,
|
|
49
51
|
connectionId: params.sourceConnectionId,
|
|
50
52
|
externalRepositoryId: params.sourceExternalRepositoryId,
|
|
51
53
|
ref: params.ref,
|
|
52
|
-
prefix:
|
|
54
|
+
prefix: workflowPath,
|
|
53
55
|
limit: MAX_WORKFLOW_FILES,
|
|
54
56
|
});
|
|
55
57
|
if (page.nextCursor) {
|
|
@@ -65,7 +67,7 @@ export async function discoverWorkflowFiles(
|
|
|
65
67
|
if (paths.length === 0) {
|
|
66
68
|
throw new DefinitionSyncPermanentError(
|
|
67
69
|
'no-workflow-files',
|
|
68
|
-
`No workflow files were found under ${
|
|
70
|
+
`No workflow files were found under ${workflowPath}`,
|
|
69
71
|
);
|
|
70
72
|
}
|
|
71
73
|
|
package/src/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
onProjectSourceCommitObserved,
|
|
25
25
|
} from '#presentation/subscribers/index.js';
|
|
26
26
|
import {createDefinitionSyncActivities, DEFINITIONS_TASK_QUEUE} from '#temporal/index.js';
|
|
27
|
+
import {definitionWorkflowPath} from './config.js';
|
|
27
28
|
|
|
28
29
|
export type {
|
|
29
30
|
WorkflowDefinition,
|
|
@@ -79,7 +80,10 @@ export function createDefinitionsModule({
|
|
|
79
80
|
{
|
|
80
81
|
taskQueue: DEFINITIONS_TASK_QUEUE,
|
|
81
82
|
workflowsPath,
|
|
82
|
-
activities: () =>
|
|
83
|
+
activities: () =>
|
|
84
|
+
createDefinitionSyncActivities(sourceControl, agent, integrations, {
|
|
85
|
+
workflowPath: definitionWorkflowPath,
|
|
86
|
+
}),
|
|
83
87
|
workflows: [],
|
|
84
88
|
},
|
|
85
89
|
],
|
|
@@ -180,6 +180,35 @@ describe('definition sync activities', () => {
|
|
|
180
180
|
});
|
|
181
181
|
});
|
|
182
182
|
|
|
183
|
+
describe('discoverDefinitionWorkflows', () => {
|
|
184
|
+
it('uses the configured workflow path', async () => {
|
|
185
|
+
const source = sourceControl({
|
|
186
|
+
listFiles: vi.fn(() =>
|
|
187
|
+
Promise.resolve({
|
|
188
|
+
files: [{path: '.shipfox/staging/workflows/ci.yml', type: 'file' as const, size: 64}],
|
|
189
|
+
nextCursor: null,
|
|
190
|
+
}),
|
|
191
|
+
),
|
|
192
|
+
});
|
|
193
|
+
const activities = createDefinitionSyncActivities(source, agent, undefined, {
|
|
194
|
+
workflowPath: '.shipfox/staging/workflows/',
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const result = await activities.discoverDefinitionWorkflows({
|
|
198
|
+
projectId,
|
|
199
|
+
workspaceId: crypto.randomUUID(),
|
|
200
|
+
sourceConnectionId,
|
|
201
|
+
sourceExternalRepositoryId: 'gitea:gitea-owner/platform',
|
|
202
|
+
sourceRef: 'main',
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
expect(result.paths).toEqual(['.shipfox/staging/workflows/ci.yml']);
|
|
206
|
+
expect(source.listFiles).toHaveBeenCalledWith(
|
|
207
|
+
expect.objectContaining({prefix: '.shipfox/staging/workflows/'}),
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
183
212
|
describe('fetchAndApplyDefinitionWorkflows', () => {
|
|
184
213
|
it('upserts workflow definitions and soft-deletes orphans', async () => {
|
|
185
214
|
const activities = createDefinitionSyncActivities(sourceControl(), agent);
|
|
@@ -52,14 +52,22 @@ export interface FetchAndApplyActivityResult {
|
|
|
52
52
|
deletedCount: number;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
export interface DefinitionSyncActivityOptions {
|
|
56
|
+
workflowPath: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
55
59
|
export function createDefinitionSyncActivities(
|
|
56
60
|
sourceControl: DefinitionsSourceControl,
|
|
57
61
|
agent: AgentInterModuleClient,
|
|
58
62
|
integrations?: IntegrationsModuleClient | undefined,
|
|
63
|
+
options?: DefinitionSyncActivityOptions | undefined,
|
|
59
64
|
) {
|
|
60
65
|
return {
|
|
61
66
|
prepareDefinitionSync: createPrepareDefinitionSyncActivity(sourceControl),
|
|
62
|
-
discoverDefinitionWorkflows: createDiscoverDefinitionWorkflowsActivity(
|
|
67
|
+
discoverDefinitionWorkflows: createDiscoverDefinitionWorkflowsActivity(
|
|
68
|
+
sourceControl,
|
|
69
|
+
options?.workflowPath,
|
|
70
|
+
),
|
|
63
71
|
fetchAndApplyDefinitionWorkflows: createFetchAndApplyActivity(
|
|
64
72
|
sourceControl,
|
|
65
73
|
agent,
|
|
@@ -94,7 +102,10 @@ function createPrepareDefinitionSyncActivity(sourceControl: DefinitionsSourceCon
|
|
|
94
102
|
};
|
|
95
103
|
}
|
|
96
104
|
|
|
97
|
-
function createDiscoverDefinitionWorkflowsActivity(
|
|
105
|
+
function createDiscoverDefinitionWorkflowsActivity(
|
|
106
|
+
sourceControl: DefinitionsSourceControl,
|
|
107
|
+
workflowPath?: string | undefined,
|
|
108
|
+
) {
|
|
98
109
|
return async function discoverDefinitionWorkflows(
|
|
99
110
|
input: SyncRefScopedInput,
|
|
100
111
|
): Promise<DiscoverWorkflowsActivityResult> {
|
|
@@ -103,6 +114,7 @@ function createDiscoverDefinitionWorkflowsActivity(sourceControl: DefinitionsSou
|
|
|
103
114
|
...input,
|
|
104
115
|
ref: input.sourceCommitSha ?? input.sourceRef,
|
|
105
116
|
sourceControl,
|
|
117
|
+
workflowPath,
|
|
106
118
|
});
|
|
107
119
|
});
|
|
108
120
|
};
|