@fractary/faber 1.0.2 → 1.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/dist/__tests__/config.test.d.ts +7 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +297 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/integration/init-workflow.test.d.ts +7 -0
- package/dist/__tests__/integration/init-workflow.test.d.ts.map +1 -0
- package/dist/__tests__/integration/init-workflow.test.js +309 -0
- package/dist/__tests__/integration/init-workflow.test.js.map +1 -0
- package/dist/config/__tests__/initializer.test.d.ts +7 -0
- package/dist/config/__tests__/initializer.test.d.ts.map +1 -0
- package/dist/config/__tests__/initializer.test.js +317 -0
- package/dist/config/__tests__/initializer.test.js.map +1 -0
- package/dist/config/initializer.d.ts +68 -0
- package/dist/config/initializer.d.ts.map +1 -0
- package/dist/config/initializer.js +230 -0
- package/dist/config/initializer.js.map +1 -0
- package/dist/config.d.ts +52 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +100 -18
- package/dist/config.js.map +1 -1
- package/dist/spec/__tests__/manager.test.d.ts +7 -0
- package/dist/spec/__tests__/manager.test.d.ts.map +1 -0
- package/dist/spec/__tests__/manager.test.js +206 -0
- package/dist/spec/__tests__/manager.test.js.map +1 -0
- package/dist/spec/manager.d.ts +9 -1
- package/dist/spec/manager.d.ts.map +1 -1
- package/dist/spec/manager.js +23 -1
- package/dist/spec/manager.js.map +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/config.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fractary/faber - Configuration Loading Tests
|
|
4
|
+
*
|
|
5
|
+
* Unit tests for config loading functions with allowMissing option
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const config_1 = require("../config");
|
|
44
|
+
const initializer_1 = require("../config/initializer");
|
|
45
|
+
const errors_1 = require("../errors");
|
|
46
|
+
describe('Config Loading Functions', () => {
|
|
47
|
+
const testDir = path.join(__dirname, '__test-config-loading__');
|
|
48
|
+
const faberConfigPath = path.join(testDir, '.fractary', 'plugins', 'faber', 'config.yaml');
|
|
49
|
+
const workConfigPath = path.join(testDir, '.fractary', 'plugins', 'work', 'config.json');
|
|
50
|
+
const repoConfigPath = path.join(testDir, '.fractary', 'plugins', 'repo', 'config.json');
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
// Clean up test directory before each test
|
|
53
|
+
if (fs.existsSync(testDir)) {
|
|
54
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
55
|
+
}
|
|
56
|
+
fs.mkdirSync(testDir, { recursive: true });
|
|
57
|
+
});
|
|
58
|
+
afterEach(() => {
|
|
59
|
+
// Clean up test directory after each test
|
|
60
|
+
if (fs.existsSync(testDir)) {
|
|
61
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
describe('loadFaberConfig', () => {
|
|
65
|
+
it('should throw when config is missing and allowMissing is not set', () => {
|
|
66
|
+
expect(() => (0, config_1.loadFaberConfig)(testDir)).toThrow(errors_1.ConfigValidationError);
|
|
67
|
+
expect(() => (0, config_1.loadFaberConfig)(testDir)).toThrow(/fractary init/);
|
|
68
|
+
});
|
|
69
|
+
it('should throw when config is missing and allowMissing is false', () => {
|
|
70
|
+
expect(() => (0, config_1.loadFaberConfig)(testDir, { allowMissing: false })).toThrow(errors_1.ConfigValidationError);
|
|
71
|
+
});
|
|
72
|
+
it('should return null when config is missing and allowMissing is true', () => {
|
|
73
|
+
const config = (0, config_1.loadFaberConfig)(testDir, { allowMissing: true });
|
|
74
|
+
expect(config).toBeNull();
|
|
75
|
+
});
|
|
76
|
+
it('should return config when it exists', () => {
|
|
77
|
+
const defaultConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
78
|
+
initializer_1.ConfigInitializer.writeConfig(defaultConfig, faberConfigPath);
|
|
79
|
+
const config = (0, config_1.loadFaberConfig)(testDir);
|
|
80
|
+
expect(config).not.toBeNull();
|
|
81
|
+
expect(config?.schema_version).toBe('1.0');
|
|
82
|
+
});
|
|
83
|
+
it('should return config when allowMissing is true and config exists', () => {
|
|
84
|
+
const defaultConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
85
|
+
initializer_1.ConfigInitializer.writeConfig(defaultConfig, faberConfigPath);
|
|
86
|
+
const config = (0, config_1.loadFaberConfig)(testDir, { allowMissing: true });
|
|
87
|
+
expect(config).not.toBeNull();
|
|
88
|
+
expect(config?.schema_version).toBe('1.0');
|
|
89
|
+
});
|
|
90
|
+
it('should construct config from individual plugin configs when FABER config missing', () => {
|
|
91
|
+
// Create work and repo configs separately
|
|
92
|
+
const workDir = path.dirname(workConfigPath);
|
|
93
|
+
const repoDir = path.dirname(repoConfigPath);
|
|
94
|
+
fs.mkdirSync(workDir, { recursive: true });
|
|
95
|
+
fs.mkdirSync(repoDir, { recursive: true });
|
|
96
|
+
fs.writeFileSync(workConfigPath, JSON.stringify({ platform: 'github' }, null, 2), 'utf-8');
|
|
97
|
+
fs.writeFileSync(repoConfigPath, JSON.stringify({ platform: 'github', owner: 'test', repo: 'test' }, null, 2), 'utf-8');
|
|
98
|
+
const config = (0, config_1.loadFaberConfig)(testDir, { allowMissing: true });
|
|
99
|
+
expect(config).not.toBeNull();
|
|
100
|
+
expect(config?.work.platform).toBe('github');
|
|
101
|
+
expect(config?.repo.platform).toBe('github');
|
|
102
|
+
});
|
|
103
|
+
it('should include helpful error message with expected path', () => {
|
|
104
|
+
try {
|
|
105
|
+
(0, config_1.loadFaberConfig)(testDir);
|
|
106
|
+
fail('Should have thrown');
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (error instanceof errors_1.ConfigValidationError) {
|
|
110
|
+
expect(error.message).toContain('Expected config at:');
|
|
111
|
+
expect(error.message).toContain('.fractary/plugins/faber');
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
fail('Wrong error type');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('loadWorkConfig', () => {
|
|
120
|
+
it('should throw when config is missing and allowMissing is not set', () => {
|
|
121
|
+
expect(() => (0, config_1.loadWorkConfig)(testDir)).toThrow(errors_1.ConfigValidationError);
|
|
122
|
+
expect(() => (0, config_1.loadWorkConfig)(testDir)).toThrow(/fractary init/);
|
|
123
|
+
});
|
|
124
|
+
it('should throw when config is missing and allowMissing is false', () => {
|
|
125
|
+
expect(() => (0, config_1.loadWorkConfig)(testDir, { allowMissing: false })).toThrow(errors_1.ConfigValidationError);
|
|
126
|
+
});
|
|
127
|
+
it('should return null when config is missing and allowMissing is true', () => {
|
|
128
|
+
const config = (0, config_1.loadWorkConfig)(testDir, { allowMissing: true });
|
|
129
|
+
expect(config).toBeNull();
|
|
130
|
+
});
|
|
131
|
+
it('should return config when it exists', () => {
|
|
132
|
+
const workDir = path.dirname(workConfigPath);
|
|
133
|
+
fs.mkdirSync(workDir, { recursive: true });
|
|
134
|
+
fs.writeFileSync(workConfigPath, JSON.stringify({ platform: 'github', owner: 'test', repo: 'test' }, null, 2), 'utf-8');
|
|
135
|
+
const config = (0, config_1.loadWorkConfig)(testDir);
|
|
136
|
+
expect(config).not.toBeNull();
|
|
137
|
+
expect(config?.platform).toBe('github');
|
|
138
|
+
});
|
|
139
|
+
it('should handle handlers structure from plugins', () => {
|
|
140
|
+
const workDir = path.dirname(workConfigPath);
|
|
141
|
+
fs.mkdirSync(workDir, { recursive: true });
|
|
142
|
+
fs.writeFileSync(workConfigPath, JSON.stringify({
|
|
143
|
+
handlers: {
|
|
144
|
+
github: {
|
|
145
|
+
platform: 'github',
|
|
146
|
+
owner: 'test',
|
|
147
|
+
repo: 'test',
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
}, null, 2), 'utf-8');
|
|
151
|
+
const config = (0, config_1.loadWorkConfig)(testDir);
|
|
152
|
+
expect(config).not.toBeNull();
|
|
153
|
+
expect(config?.platform).toBe('github');
|
|
154
|
+
expect(config?.owner).toBe('test');
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
describe('loadRepoConfig', () => {
|
|
158
|
+
it('should throw when config is missing and allowMissing is not set', () => {
|
|
159
|
+
expect(() => (0, config_1.loadRepoConfig)(testDir)).toThrow(errors_1.ConfigValidationError);
|
|
160
|
+
expect(() => (0, config_1.loadRepoConfig)(testDir)).toThrow(/fractary init/);
|
|
161
|
+
});
|
|
162
|
+
it('should throw when config is missing and allowMissing is false', () => {
|
|
163
|
+
expect(() => (0, config_1.loadRepoConfig)(testDir, { allowMissing: false })).toThrow(errors_1.ConfigValidationError);
|
|
164
|
+
});
|
|
165
|
+
it('should return null when config is missing and allowMissing is true', () => {
|
|
166
|
+
const config = (0, config_1.loadRepoConfig)(testDir, { allowMissing: true });
|
|
167
|
+
expect(config).toBeNull();
|
|
168
|
+
});
|
|
169
|
+
it('should return config when it exists', () => {
|
|
170
|
+
const repoDir = path.dirname(repoConfigPath);
|
|
171
|
+
fs.mkdirSync(repoDir, { recursive: true });
|
|
172
|
+
fs.writeFileSync(repoConfigPath, JSON.stringify({
|
|
173
|
+
platform: 'github',
|
|
174
|
+
owner: 'test',
|
|
175
|
+
repo: 'test',
|
|
176
|
+
defaultBranch: 'main',
|
|
177
|
+
}, null, 2), 'utf-8');
|
|
178
|
+
const config = (0, config_1.loadRepoConfig)(testDir);
|
|
179
|
+
expect(config).not.toBeNull();
|
|
180
|
+
expect(config?.platform).toBe('github');
|
|
181
|
+
expect(config?.defaultBranch).toBe('main');
|
|
182
|
+
});
|
|
183
|
+
it('should handle handlers structure from plugins', () => {
|
|
184
|
+
const repoDir = path.dirname(repoConfigPath);
|
|
185
|
+
fs.mkdirSync(repoDir, { recursive: true });
|
|
186
|
+
fs.writeFileSync(repoConfigPath, JSON.stringify({
|
|
187
|
+
handlers: {
|
|
188
|
+
github: {
|
|
189
|
+
platform: 'github',
|
|
190
|
+
owner: 'test',
|
|
191
|
+
repo: 'test',
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
}, null, 2), 'utf-8');
|
|
195
|
+
const config = (0, config_1.loadRepoConfig)(testDir);
|
|
196
|
+
expect(config).not.toBeNull();
|
|
197
|
+
expect(config?.platform).toBe('github');
|
|
198
|
+
expect(config?.owner).toBe('test');
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
describe('loadSpecConfig', () => {
|
|
202
|
+
it('should throw when config is missing and allowMissing is not set', () => {
|
|
203
|
+
expect(() => (0, config_1.loadSpecConfig)(testDir)).toThrow(errors_1.ConfigValidationError);
|
|
204
|
+
expect(() => (0, config_1.loadSpecConfig)(testDir)).toThrow(/fractary init/);
|
|
205
|
+
});
|
|
206
|
+
it('should throw when config is missing and allowMissing is false', () => {
|
|
207
|
+
expect(() => (0, config_1.loadSpecConfig)(testDir, { allowMissing: false })).toThrow(errors_1.ConfigValidationError);
|
|
208
|
+
});
|
|
209
|
+
it('should return default config when FABER config is missing and allowMissing is true', () => {
|
|
210
|
+
const config = (0, config_1.loadSpecConfig)(testDir, { allowMissing: true });
|
|
211
|
+
expect(config).not.toBeNull();
|
|
212
|
+
expect(config.localPath).toBe(path.join(testDir, 'specs'));
|
|
213
|
+
});
|
|
214
|
+
it('should return spec config from FABER config when it exists', () => {
|
|
215
|
+
const defaultConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
216
|
+
defaultConfig.artifacts.specs.local_path = '/custom/specs';
|
|
217
|
+
initializer_1.ConfigInitializer.writeConfig(defaultConfig, faberConfigPath);
|
|
218
|
+
const config = (0, config_1.loadSpecConfig)(testDir);
|
|
219
|
+
expect(config.localPath).toBe('/custom/specs');
|
|
220
|
+
});
|
|
221
|
+
it('should return default config when allowMissing is true and FABER config exists but has no specs config', () => {
|
|
222
|
+
const defaultConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
223
|
+
delete defaultConfig.artifacts.specs;
|
|
224
|
+
initializer_1.ConfigInitializer.writeConfig(defaultConfig, faberConfigPath);
|
|
225
|
+
const config = (0, config_1.loadSpecConfig)(testDir, { allowMissing: true });
|
|
226
|
+
expect(config.localPath).toBe(path.join(testDir, 'specs'));
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
describe('loadLogConfig', () => {
|
|
230
|
+
it('should return default config when FABER config is missing', () => {
|
|
231
|
+
const config = (0, config_1.loadLogConfig)(testDir);
|
|
232
|
+
expect(config).not.toBeNull();
|
|
233
|
+
expect(config.localPath).toBe(path.join(testDir, '.fractary', 'logs'));
|
|
234
|
+
});
|
|
235
|
+
it('should return log config from FABER config when it exists', () => {
|
|
236
|
+
const defaultConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
237
|
+
defaultConfig.artifacts.logs.local_path = '/custom/logs';
|
|
238
|
+
initializer_1.ConfigInitializer.writeConfig(defaultConfig, faberConfigPath);
|
|
239
|
+
const config = (0, config_1.loadLogConfig)(testDir);
|
|
240
|
+
expect(config.localPath).toBe('/custom/logs');
|
|
241
|
+
});
|
|
242
|
+
it('should return default config when FABER config exists but has no logs config', () => {
|
|
243
|
+
const defaultConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
244
|
+
delete defaultConfig.artifacts.logs;
|
|
245
|
+
initializer_1.ConfigInitializer.writeConfig(defaultConfig, faberConfigPath);
|
|
246
|
+
const config = (0, config_1.loadLogConfig)(testDir);
|
|
247
|
+
expect(config.localPath).toBe(path.join(testDir, '.fractary', 'logs'));
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
describe('loadStateConfig', () => {
|
|
251
|
+
it('should return default config when FABER config is missing', () => {
|
|
252
|
+
const config = (0, config_1.loadStateConfig)(testDir);
|
|
253
|
+
expect(config).not.toBeNull();
|
|
254
|
+
expect(config.localPath).toBe(path.join(testDir, '.faber', 'state'));
|
|
255
|
+
});
|
|
256
|
+
it('should return state config from FABER config when it exists', () => {
|
|
257
|
+
const defaultConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
258
|
+
defaultConfig.artifacts.state.local_path = '/custom/state';
|
|
259
|
+
initializer_1.ConfigInitializer.writeConfig(defaultConfig, faberConfigPath);
|
|
260
|
+
const config = (0, config_1.loadStateConfig)(testDir);
|
|
261
|
+
expect(config.localPath).toBe('/custom/state');
|
|
262
|
+
});
|
|
263
|
+
it('should return default config when FABER config exists but has no state config', () => {
|
|
264
|
+
const defaultConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
265
|
+
delete defaultConfig.artifacts.state;
|
|
266
|
+
initializer_1.ConfigInitializer.writeConfig(defaultConfig, faberConfigPath);
|
|
267
|
+
const config = (0, config_1.loadStateConfig)(testDir);
|
|
268
|
+
expect(config.localPath).toBe(path.join(testDir, '.faber', 'state'));
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
describe('Backward Compatibility', () => {
|
|
272
|
+
it('should read existing JSON configs during migration period', () => {
|
|
273
|
+
// Create legacy JSON config
|
|
274
|
+
const jsonConfigPath = faberConfigPath.replace(/\.yaml$/, '.json');
|
|
275
|
+
const dir = path.dirname(jsonConfigPath);
|
|
276
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
277
|
+
const jsonConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
278
|
+
jsonConfig.repo.owner = 'json-owner';
|
|
279
|
+
fs.writeFileSync(jsonConfigPath, JSON.stringify(jsonConfig, null, 2), 'utf-8');
|
|
280
|
+
const config = (0, config_1.loadFaberConfig)(testDir);
|
|
281
|
+
expect(config).not.toBeNull();
|
|
282
|
+
expect(config?.repo.owner).toBe('json-owner');
|
|
283
|
+
});
|
|
284
|
+
it('should prefer YAML over JSON when both exist', () => {
|
|
285
|
+
const yamlConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
286
|
+
yamlConfig.repo.owner = 'yaml-owner';
|
|
287
|
+
initializer_1.ConfigInitializer.writeConfig(yamlConfig, faberConfigPath);
|
|
288
|
+
const jsonConfigPath = faberConfigPath.replace(/\.yaml$/, '.json');
|
|
289
|
+
const jsonConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
290
|
+
jsonConfig.repo.owner = 'json-owner';
|
|
291
|
+
fs.writeFileSync(jsonConfigPath, JSON.stringify(jsonConfig, null, 2), 'utf-8');
|
|
292
|
+
const config = (0, config_1.loadFaberConfig)(testDir);
|
|
293
|
+
expect(config?.repo.owner).toBe('yaml-owner');
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
//# sourceMappingURL=config.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.test.js","sourceRoot":"","sources":["../../src/__tests__/config.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-workflow.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/init-workflow.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fractary/faber - Init Workflow Integration Tests
|
|
4
|
+
*
|
|
5
|
+
* Integration tests for the full initialization workflow
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const initializer_1 = require("../../config/initializer");
|
|
44
|
+
const config_1 = require("../../config");
|
|
45
|
+
const manager_1 = require("../../spec/manager");
|
|
46
|
+
describe('Init Workflow Integration', () => {
|
|
47
|
+
const testDir = path.join(__dirname, '__test-init-workflow__');
|
|
48
|
+
const configPath = path.join(testDir, '.fractary', 'plugins', 'faber', 'config.yaml');
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
// Clean up test directory before each test
|
|
51
|
+
if (fs.existsSync(testDir)) {
|
|
52
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
53
|
+
}
|
|
54
|
+
fs.mkdirSync(testDir, { recursive: true });
|
|
55
|
+
// Mock process.cwd() to return testDir
|
|
56
|
+
jest.spyOn(process, 'cwd').mockReturnValue(testDir);
|
|
57
|
+
});
|
|
58
|
+
afterEach(() => {
|
|
59
|
+
// Clean up test directory after each test
|
|
60
|
+
if (fs.existsSync(testDir)) {
|
|
61
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
62
|
+
}
|
|
63
|
+
// Restore mocks
|
|
64
|
+
jest.restoreAllMocks();
|
|
65
|
+
});
|
|
66
|
+
describe('CLI Init Command Simulation', () => {
|
|
67
|
+
it('should allow init without existing config', () => {
|
|
68
|
+
// Simulate CLI init command
|
|
69
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
70
|
+
initializer_1.ConfigInitializer.writeConfig(config, configPath);
|
|
71
|
+
// Verify config was created
|
|
72
|
+
expect(fs.existsSync(configPath)).toBe(true);
|
|
73
|
+
// Verify config can be loaded
|
|
74
|
+
const loadedConfig = (0, config_1.loadFaberConfig)(testDir);
|
|
75
|
+
expect(loadedConfig).not.toBeNull();
|
|
76
|
+
expect(loadedConfig?.schema_version).toBe('1.0');
|
|
77
|
+
});
|
|
78
|
+
it('should create YAML config that is human-readable', () => {
|
|
79
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
80
|
+
initializer_1.ConfigInitializer.writeConfig(config, configPath);
|
|
81
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
82
|
+
// Verify YAML format
|
|
83
|
+
expect(content).toContain('schema_version:');
|
|
84
|
+
expect(content).toContain('work:');
|
|
85
|
+
expect(content).toContain('platform: github');
|
|
86
|
+
expect(content).toContain('repo:');
|
|
87
|
+
expect(content).toContain('artifacts:');
|
|
88
|
+
expect(content).toContain('workflow:');
|
|
89
|
+
expect(content).toContain('autonomy: guarded');
|
|
90
|
+
// Should not contain JSON-specific syntax
|
|
91
|
+
expect(content).not.toContain('{');
|
|
92
|
+
expect(content).not.toContain('"schema_version"');
|
|
93
|
+
});
|
|
94
|
+
it('should create config with all required fields populated', () => {
|
|
95
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
96
|
+
initializer_1.ConfigInitializer.writeConfig(config, configPath);
|
|
97
|
+
const loadedConfig = (0, config_1.loadFaberConfig)(testDir);
|
|
98
|
+
expect(loadedConfig).not.toBeNull();
|
|
99
|
+
expect(loadedConfig?.schema_version).toBe('1.0');
|
|
100
|
+
expect(loadedConfig?.work).toBeDefined();
|
|
101
|
+
expect(loadedConfig?.repo).toBeDefined();
|
|
102
|
+
expect(loadedConfig?.artifacts).toBeDefined();
|
|
103
|
+
expect(loadedConfig?.workflow).toBeDefined();
|
|
104
|
+
});
|
|
105
|
+
it('should allow customization during init', () => {
|
|
106
|
+
const createdPath = initializer_1.ConfigInitializer.initializeProject(testDir, {
|
|
107
|
+
repoOwner: 'my-org',
|
|
108
|
+
repoName: 'my-project',
|
|
109
|
+
workPlatform: 'jira',
|
|
110
|
+
repoPlatform: 'gitlab',
|
|
111
|
+
});
|
|
112
|
+
expect(fs.existsSync(createdPath)).toBe(true);
|
|
113
|
+
const config = (0, config_1.loadFaberConfig)(testDir);
|
|
114
|
+
expect(config?.repo.owner).toBe('my-org');
|
|
115
|
+
expect(config?.repo.repo).toBe('my-project');
|
|
116
|
+
expect(config?.work.platform).toBe('jira');
|
|
117
|
+
expect(config?.repo.platform).toBe('gitlab');
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe('SpecManager Integration After Init', () => {
|
|
121
|
+
it('should allow SpecManager creation before init', () => {
|
|
122
|
+
// Before init - should work with defaults
|
|
123
|
+
const managerBefore = new manager_1.SpecManager();
|
|
124
|
+
expect(managerBefore).toBeDefined();
|
|
125
|
+
// After init - should use config
|
|
126
|
+
initializer_1.ConfigInitializer.initializeProject(testDir);
|
|
127
|
+
const managerAfter = new manager_1.SpecManager();
|
|
128
|
+
expect(managerAfter).toBeDefined();
|
|
129
|
+
});
|
|
130
|
+
it('should use config path after init', () => {
|
|
131
|
+
// Create manager before config exists
|
|
132
|
+
const manager1 = new manager_1.SpecManager();
|
|
133
|
+
expect(manager1).toBeDefined();
|
|
134
|
+
// Initialize with custom specs path
|
|
135
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
136
|
+
config.artifacts.specs.local_path = '/custom/specs';
|
|
137
|
+
initializer_1.ConfigInitializer.writeConfig(config, configPath);
|
|
138
|
+
// New manager should use config path
|
|
139
|
+
const manager2 = new manager_1.SpecManager();
|
|
140
|
+
expect(manager2).toBeDefined();
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
describe('Config Loading After Init', () => {
|
|
144
|
+
it('should load all config sections after init', () => {
|
|
145
|
+
initializer_1.ConfigInitializer.initializeProject(testDir);
|
|
146
|
+
const faberConfig = (0, config_1.loadFaberConfig)(testDir);
|
|
147
|
+
const workConfig = (0, config_1.loadWorkConfig)(testDir);
|
|
148
|
+
const repoConfig = (0, config_1.loadRepoConfig)(testDir);
|
|
149
|
+
const specConfig = (0, config_1.loadSpecConfig)(testDir);
|
|
150
|
+
expect(faberConfig).not.toBeNull();
|
|
151
|
+
expect(workConfig).not.toBeNull();
|
|
152
|
+
expect(repoConfig).not.toBeNull();
|
|
153
|
+
expect(specConfig).toBeDefined();
|
|
154
|
+
});
|
|
155
|
+
it('should not throw after successful init', () => {
|
|
156
|
+
initializer_1.ConfigInitializer.initializeProject(testDir);
|
|
157
|
+
// All of these should work without throwing
|
|
158
|
+
expect(() => (0, config_1.loadFaberConfig)(testDir)).not.toThrow();
|
|
159
|
+
expect(() => (0, config_1.loadWorkConfig)(testDir)).not.toThrow();
|
|
160
|
+
expect(() => (0, config_1.loadRepoConfig)(testDir)).not.toThrow();
|
|
161
|
+
expect(() => (0, config_1.loadSpecConfig)(testDir)).not.toThrow();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
describe('Error Messages Without Init', () => {
|
|
165
|
+
it('should provide helpful error message when config missing', () => {
|
|
166
|
+
try {
|
|
167
|
+
(0, config_1.loadFaberConfig)(testDir);
|
|
168
|
+
fail('Should have thrown');
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
expect(error.message).toContain('fractary init');
|
|
172
|
+
expect(error.message).toContain('Expected config at:');
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
it('should guide user to run init command', () => {
|
|
176
|
+
try {
|
|
177
|
+
(0, config_1.loadWorkConfig)(testDir);
|
|
178
|
+
fail('Should have thrown');
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
expect(error.message).toContain('fractary init');
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
(0, config_1.loadRepoConfig)(testDir);
|
|
185
|
+
fail('Should have thrown');
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
expect(error.message).toContain('fractary init');
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
(0, config_1.loadSpecConfig)(testDir);
|
|
192
|
+
fail('Should have thrown');
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
expect(error.message).toContain('fractary init');
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
describe('Backward Compatibility', () => {
|
|
200
|
+
it('should work with existing JSON configs during migration', () => {
|
|
201
|
+
// Create legacy JSON config
|
|
202
|
+
const jsonConfigPath = configPath.replace(/\.yaml$/, '.json');
|
|
203
|
+
const dir = path.dirname(jsonConfigPath);
|
|
204
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
205
|
+
const jsonConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
206
|
+
jsonConfig.repo.owner = 'legacy-owner';
|
|
207
|
+
fs.writeFileSync(jsonConfigPath, JSON.stringify(jsonConfig, null, 2), 'utf-8');
|
|
208
|
+
// Should still be loadable
|
|
209
|
+
const config = (0, config_1.loadFaberConfig)(testDir);
|
|
210
|
+
expect(config).not.toBeNull();
|
|
211
|
+
expect(config?.repo.owner).toBe('legacy-owner');
|
|
212
|
+
// SpecManager should work
|
|
213
|
+
const manager = new manager_1.SpecManager();
|
|
214
|
+
expect(manager).toBeDefined();
|
|
215
|
+
});
|
|
216
|
+
it('should migrate from JSON to YAML when re-initializing', () => {
|
|
217
|
+
// Create legacy JSON config
|
|
218
|
+
const jsonConfigPath = configPath.replace(/\.yaml$/, '.json');
|
|
219
|
+
const dir = path.dirname(jsonConfigPath);
|
|
220
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
221
|
+
const jsonConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
222
|
+
fs.writeFileSync(jsonConfigPath, JSON.stringify(jsonConfig, null, 2), 'utf-8');
|
|
223
|
+
// Re-initialize (creates YAML)
|
|
224
|
+
initializer_1.ConfigInitializer.initializeProject(testDir);
|
|
225
|
+
// Both should exist during migration
|
|
226
|
+
expect(fs.existsSync(jsonConfigPath)).toBe(true);
|
|
227
|
+
expect(fs.existsSync(configPath)).toBe(true);
|
|
228
|
+
// YAML should be preferred
|
|
229
|
+
const config = initializer_1.ConfigInitializer.readConfig(configPath);
|
|
230
|
+
expect(config).not.toBeNull();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
describe('Real-World Scenarios', () => {
|
|
234
|
+
it('should support new project initialization flow', () => {
|
|
235
|
+
// 1. User runs: fractary init
|
|
236
|
+
const createdPath = initializer_1.ConfigInitializer.initializeProject(testDir, {
|
|
237
|
+
repoOwner: 'acme',
|
|
238
|
+
repoName: 'my-app',
|
|
239
|
+
});
|
|
240
|
+
expect(fs.existsSync(createdPath)).toBe(true);
|
|
241
|
+
// 2. User runs: fractary spec:create
|
|
242
|
+
const manager = new manager_1.SpecManager();
|
|
243
|
+
expect(manager).toBeDefined();
|
|
244
|
+
// 3. Config should be loaded correctly
|
|
245
|
+
const config = (0, config_1.loadFaberConfig)(testDir);
|
|
246
|
+
expect(config?.repo.owner).toBe('acme');
|
|
247
|
+
expect(config?.repo.repo).toBe('my-app');
|
|
248
|
+
});
|
|
249
|
+
it('should support existing project with partial config', () => {
|
|
250
|
+
// 1. Create work and repo configs separately (old setup)
|
|
251
|
+
const workConfigPath = path.join(testDir, '.fractary', 'plugins', 'work', 'config.json');
|
|
252
|
+
const repoConfigPath = path.join(testDir, '.fractary', 'plugins', 'repo', 'config.json');
|
|
253
|
+
fs.mkdirSync(path.dirname(workConfigPath), { recursive: true });
|
|
254
|
+
fs.mkdirSync(path.dirname(repoConfigPath), { recursive: true });
|
|
255
|
+
fs.writeFileSync(workConfigPath, JSON.stringify({ platform: 'github', owner: 'old', repo: 'old' }, null, 2), 'utf-8');
|
|
256
|
+
fs.writeFileSync(repoConfigPath, JSON.stringify({ platform: 'github', owner: 'old', repo: 'old' }, null, 2), 'utf-8');
|
|
257
|
+
// 2. Load config (should construct from individual configs)
|
|
258
|
+
const config = (0, config_1.loadFaberConfig)(testDir, { allowMissing: true });
|
|
259
|
+
expect(config).not.toBeNull();
|
|
260
|
+
expect(config?.work.platform).toBe('github');
|
|
261
|
+
expect(config?.repo.platform).toBe('github');
|
|
262
|
+
// 3. Upgrade to unified config
|
|
263
|
+
initializer_1.ConfigInitializer.initializeProject(testDir, {
|
|
264
|
+
repoOwner: 'new',
|
|
265
|
+
repoName: 'new',
|
|
266
|
+
});
|
|
267
|
+
// 4. New config should take precedence
|
|
268
|
+
const newConfig = (0, config_1.loadFaberConfig)(testDir);
|
|
269
|
+
expect(newConfig?.repo.owner).toBe('new');
|
|
270
|
+
});
|
|
271
|
+
it('should support CLI integration pattern', () => {
|
|
272
|
+
// Simulate CLI checking for config before running command
|
|
273
|
+
const configExists = initializer_1.ConfigInitializer.configExists(configPath);
|
|
274
|
+
expect(configExists).toBe(false);
|
|
275
|
+
// CLI detects no config and prompts user to init
|
|
276
|
+
if (!configExists) {
|
|
277
|
+
initializer_1.ConfigInitializer.initializeProject(testDir);
|
|
278
|
+
}
|
|
279
|
+
// Now config exists
|
|
280
|
+
expect(initializer_1.ConfigInitializer.configExists(configPath)).toBe(true);
|
|
281
|
+
// CLI can now run commands
|
|
282
|
+
const manager = new manager_1.SpecManager();
|
|
283
|
+
expect(manager).toBeDefined();
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
describe('Performance Requirements', () => {
|
|
287
|
+
it('should generate default config in under 100ms', () => {
|
|
288
|
+
const start = Date.now();
|
|
289
|
+
initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
290
|
+
const duration = Date.now() - start;
|
|
291
|
+
expect(duration).toBeLessThan(100);
|
|
292
|
+
});
|
|
293
|
+
it('should write config file quickly', () => {
|
|
294
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
295
|
+
const start = Date.now();
|
|
296
|
+
initializer_1.ConfigInitializer.writeConfig(config, configPath);
|
|
297
|
+
const duration = Date.now() - start;
|
|
298
|
+
expect(duration).toBeLessThan(100);
|
|
299
|
+
});
|
|
300
|
+
it('should handle concurrent SpecManager creation', () => {
|
|
301
|
+
initializer_1.ConfigInitializer.initializeProject(testDir);
|
|
302
|
+
// Create multiple managers concurrently (simulates parallel operations)
|
|
303
|
+
const managers = Array(10).fill(null).map(() => new manager_1.SpecManager());
|
|
304
|
+
expect(managers).toHaveLength(10);
|
|
305
|
+
managers.forEach(manager => expect(manager).toBeDefined());
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
//# sourceMappingURL=init-workflow.test.js.map
|