Skip to content

Commit a0366ca

Browse files
committed
refactor(provision-kit): move install source config
1 parent 544a804 commit a0366ca

7 files changed

Lines changed: 149 additions & 2 deletions

File tree

‎packages/provision-kit/package.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
"types": "./src/install-source.ts",
2929
"default": "./src/install-source.ts"
3030
},
31+
"./install-source-config": {
32+
"types": "./src/install-source-config.ts",
33+
"default": "./src/install-source-config.ts"
34+
},
3135
"./install-source-network": {
3236
"types": "./src/install-source-network.ts",
3337
"default": "./src/install-source-network.ts"
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import assert from 'node:assert/strict';
2+
import { test } from 'vitest';
3+
import { AppError } from '@agent-device/kernel/errors';
4+
import {
5+
parseGitHubActionsArtifactInstallSourceSpec,
6+
parseInstallSourceConfig,
7+
} from './install-source-config.ts';
8+
9+
function assertInvalidArgs(action: () => unknown, message: string): void {
10+
assert.throws(action, (error: unknown) => {
11+
if (!(error instanceof AppError)) return false;
12+
assert.equal(error.code, 'INVALID_ARGS');
13+
assert.equal(error.message, message);
14+
assert.equal(error.details, undefined);
15+
assert.equal(error.cause, undefined);
16+
return true;
17+
});
18+
}
19+
20+
test('parses artifact IDs and names into the exact install-source shapes', () => {
21+
assert.deepEqual(
22+
parseGitHubActionsArtifactInstallSourceSpec(' callstack / agent-device : 6635342232 '),
23+
{
24+
kind: 'github-actions-artifact',
25+
owner: 'callstack',
26+
repo: 'agent-device',
27+
artifactId: 6635342232,
28+
},
29+
);
30+
assert.deepEqual(
31+
parseGitHubActionsArtifactInstallSourceSpec(
32+
'thymikee/RNCLI83: rn-android-emulator-debug-pr-19',
33+
),
34+
{
35+
kind: 'github-actions-artifact',
36+
owner: 'thymikee',
37+
repo: 'RNCLI83',
38+
artifactName: 'rn-android-emulator-debug-pr-19',
39+
},
40+
);
41+
});
42+
43+
test('rejects empty or malformed owner/repo:artifact specs with typed errors', () => {
44+
for (const spec of ['', ' ', ':artifact', 'owner/repo:', 'owner:artifact']) {
45+
assertInvalidArgs(
46+
() => parseGitHubActionsArtifactInstallSourceSpec(spec),
47+
spec === 'owner:artifact'
48+
? '--github-actions-artifact must use owner/repo.'
49+
: '--github-actions-artifact must use owner/repo:artifact, for example thymikee/RNCLI83:6635342232',
50+
);
51+
}
52+
53+
for (const spec of ['/repo:artifact', 'owner/:artifact', 'owner/repo/other:artifact']) {
54+
assertInvalidArgs(
55+
() => parseGitHubActionsArtifactInstallSourceSpec(spec),
56+
'--github-actions-artifact must use owner/repo.',
57+
);
58+
}
59+
});
60+
61+
test('parses config fields with whitespace and preserves artifact field names', () => {
62+
const sourceLabel = 'user config file /tmp/agent-device.json';
63+
assert.deepEqual(
64+
parseInstallSourceConfig(
65+
{
66+
type: ' github-actions-artifact ',
67+
repo: ' thymikee / RNCLI83 ',
68+
artifact: ' 6635342232 ',
69+
},
70+
sourceLabel,
71+
),
72+
{
73+
kind: 'github-actions-artifact',
74+
owner: 'thymikee',
75+
repo: 'RNCLI83',
76+
artifactId: 6635342232,
77+
},
78+
);
79+
assert.deepEqual(
80+
parseInstallSourceConfig(
81+
{
82+
type: 'github-actions-artifact',
83+
repo: 'callstack/agent-device',
84+
artifact: 'nightly-release',
85+
},
86+
sourceLabel,
87+
),
88+
{
89+
kind: 'github-actions-artifact',
90+
owner: 'callstack',
91+
repo: 'agent-device',
92+
artifactName: 'nightly-release',
93+
},
94+
);
95+
});
96+
97+
test('rejects empty and malformed config fields with typed errors and no cause', () => {
98+
const sourceLabel = 'project config file /tmp/agent-device.json';
99+
assertInvalidArgs(
100+
() => parseInstallSourceConfig(undefined, sourceLabel),
101+
`${sourceLabel} installSource must be an object.`,
102+
);
103+
assertInvalidArgs(
104+
() => parseInstallSourceConfig([], sourceLabel),
105+
`${sourceLabel} installSource must be an object.`,
106+
);
107+
assertInvalidArgs(
108+
() =>
109+
parseInstallSourceConfig({ type: ' ', repo: 'owner/repo', artifact: 'build' }, sourceLabel),
110+
`${sourceLabel} installSource.type must be a non-empty string.`,
111+
);
112+
assertInvalidArgs(
113+
() =>
114+
parseInstallSourceConfig({ type: 'url', repo: 'owner/repo', artifact: 'build' }, sourceLabel),
115+
`${sourceLabel} installSource.type must be "github-actions-artifact".`,
116+
);
117+
assertInvalidArgs(
118+
() =>
119+
parseInstallSourceConfig(
120+
{ type: 'github-actions-artifact', repo: 'owner/repo/other', artifact: 'build' },
121+
sourceLabel,
122+
),
123+
`${sourceLabel} installSource.repo must use owner/repo.`,
124+
);
125+
assertInvalidArgs(
126+
() =>
127+
parseInstallSourceConfig(
128+
{ type: 'github-actions-artifact', repo: 'owner/repo', artifact: ' ' },
129+
sourceLabel,
130+
),
131+
`${sourceLabel} installSource.artifact must be a non-empty string.`,
132+
);
133+
assertInvalidArgs(
134+
() =>
135+
parseInstallSourceConfig(
136+
{ type: 'github-actions-artifact', repo: 'owner/repo', artifact: 1.5 },
137+
sourceLabel,
138+
),
139+
`${sourceLabel} installSource.artifact must be an integer.`,
140+
);
141+
});
File renamed without changes.

‎scripts/layering/package-boundaries.test.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ test('the real tree parses, declares, and passes R11', () => {
487487
'@agent-device/provision-kit/boot-diagnostics',
488488
'@agent-device/provision-kit/install-artifact-archive-context',
489489
'@agent-device/provision-kit/install-source',
490+
'@agent-device/provision-kit/install-source-config',
490491
'@agent-device/provision-kit/install-source-network',
491492
'@agent-device/provision-kit/install-source-network-transport',
492493
'@agent-device/provision-kit/toolchain-probe',

‎src/__tests__/eager-closure-budgets.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ export const FACADE_BUDGETS: Readonly<Record<string, number>> = Object.freeze({
159159
'packages/provision-kit/src/boot-diagnostics.ts': 3,
160160
'packages/provision-kit/src/install-artifact-archive-context.ts': 10,
161161
'packages/provision-kit/src/install-source.ts': 26,
162+
'packages/provision-kit/src/install-source-config.ts': 3,
162163
'packages/provision-kit/src/install-source-network.ts': 3,
163164
'packages/provision-kit/src/install-source-network-transport.ts': 1,
164165
'packages/provision-kit/src/toolchain-probe.ts': 8,

‎src/cli-schema/cli-config.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
getOptionSpec,
1111
parseOptionValueFromSource,
1212
} from './option-schema.ts';
13-
import { parseInstallSourceConfig } from '../utils/install-source-config.ts';
13+
import { parseInstallSourceConfig } from '@agent-device/provision-kit/install-source-config';
1414
import { RETIRED_SCREENSHOT_MAX_SIZE } from '@agent-device/contracts/capture';
1515
import { type EnvMap } from '@agent-device/kernel/source-value';
1616

‎src/commands/management/install.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { DaemonInstallSource } from '@agent-device/kernel/contracts';
33
import type { CliFlags } from '@agent-device/contracts/command';
44
import type { CommandSchemaOverride } from '../../cli-schema/types.ts';
55
import { AppError } from '@agent-device/kernel/errors';
6-
import { parseGitHubActionsArtifactInstallSourceSpec } from '../../utils/install-source-config.ts';
6+
import { parseGitHubActionsArtifactInstallSourceSpec } from '@agent-device/provision-kit/install-source-config';
77
import {
88
booleanField,
99
jsonSchemaField,

0 commit comments

Comments
 (0)