@vizzly-testing/cli 0.19.2 → 0.20.1-beta.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/api/client.js +134 -0
- package/dist/api/core.js +341 -0
- package/dist/api/endpoints.js +314 -0
- package/dist/api/index.js +19 -0
- package/dist/auth/client.js +91 -0
- package/dist/auth/core.js +176 -0
- package/dist/auth/index.js +30 -0
- package/dist/auth/operations.js +148 -0
- package/dist/cli.js +1 -1
- package/dist/client/index.js +0 -1
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/finalize.js +41 -15
- package/dist/commands/login.js +7 -6
- package/dist/commands/logout.js +4 -4
- package/dist/commands/project.js +5 -4
- package/dist/commands/run.js +158 -90
- package/dist/commands/status.js +22 -18
- package/dist/commands/tdd.js +105 -78
- package/dist/commands/upload.js +61 -26
- package/dist/commands/whoami.js +4 -4
- package/dist/config/core.js +438 -0
- package/dist/config/index.js +13 -0
- package/dist/config/operations.js +327 -0
- package/dist/index.js +1 -1
- package/dist/project/core.js +295 -0
- package/dist/project/index.js +13 -0
- package/dist/project/operations.js +393 -0
- package/dist/report-generator/core.js +315 -0
- package/dist/report-generator/index.js +8 -0
- package/dist/report-generator/operations.js +196 -0
- package/dist/reporter/reporter-bundle.iife.js +16 -16
- package/dist/screenshot-server/core.js +157 -0
- package/dist/screenshot-server/index.js +11 -0
- package/dist/screenshot-server/operations.js +183 -0
- package/dist/sdk/index.js +3 -2
- package/dist/server/handlers/api-handler.js +14 -5
- package/dist/server/handlers/tdd-handler.js +80 -48
- package/dist/server-manager/core.js +183 -0
- package/dist/server-manager/index.js +81 -0
- package/dist/server-manager/operations.js +208 -0
- package/dist/services/build-manager.js +2 -69
- package/dist/services/index.js +21 -48
- package/dist/services/screenshot-server.js +40 -74
- package/dist/services/server-manager.js +45 -80
- package/dist/services/static-report-generator.js +21 -163
- package/dist/services/test-runner.js +90 -249
- package/dist/services/uploader.js +56 -358
- package/dist/tdd/core/hotspot-coverage.js +112 -0
- package/dist/tdd/core/signature.js +101 -0
- package/dist/tdd/index.js +19 -0
- package/dist/tdd/metadata/baseline-metadata.js +103 -0
- package/dist/tdd/metadata/hotspot-metadata.js +93 -0
- package/dist/tdd/services/baseline-downloader.js +151 -0
- package/dist/tdd/services/baseline-manager.js +166 -0
- package/dist/tdd/services/comparison-service.js +230 -0
- package/dist/tdd/services/hotspot-service.js +71 -0
- package/dist/tdd/services/result-service.js +123 -0
- package/dist/tdd/tdd-service.js +1081 -0
- package/dist/test-runner/core.js +255 -0
- package/dist/test-runner/index.js +13 -0
- package/dist/test-runner/operations.js +483 -0
- package/dist/types/client.d.ts +4 -2
- package/dist/types/index.d.ts +5 -0
- package/dist/uploader/core.js +396 -0
- package/dist/uploader/index.js +11 -0
- package/dist/uploader/operations.js +412 -0
- package/dist/utils/config-schema.js +8 -3
- package/package.json +7 -12
- package/dist/services/api-service.js +0 -412
- package/dist/services/auth-service.js +0 -226
- package/dist/services/config-service.js +0 -369
- package/dist/services/html-report-generator.js +0 -455
- package/dist/services/project-service.js +0 -326
- package/dist/services/report-generator/report.css +0 -411
- package/dist/services/report-generator/viewer.js +0 -102
- package/dist/services/tdd-service.js +0 -1429
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Manager Core - Pure functions for server management logic
|
|
3
|
+
*
|
|
4
|
+
* No I/O, no side effects - just data transformations.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Default Configuration
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Default server port
|
|
13
|
+
*/
|
|
14
|
+
export let DEFAULT_PORT = 47392;
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Config Extraction
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Extract server port from config
|
|
22
|
+
* @param {Object|undefined} config - Configuration object
|
|
23
|
+
* @returns {number} Server port
|
|
24
|
+
*/
|
|
25
|
+
export function getPort(config) {
|
|
26
|
+
return config?.server?.port || DEFAULT_PORT;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check if API key is present in config
|
|
31
|
+
* @param {Object|undefined} config - Configuration object
|
|
32
|
+
* @returns {boolean} Whether API key exists
|
|
33
|
+
*/
|
|
34
|
+
export function hasApiKey(config) {
|
|
35
|
+
return Boolean(config?.apiKey);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Server Info Building
|
|
40
|
+
// ============================================================================
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Build server info object for server.json
|
|
44
|
+
* @param {Object} options - Options
|
|
45
|
+
* @param {number} options.port - Server port
|
|
46
|
+
* @param {number} options.pid - Process ID
|
|
47
|
+
* @param {number} options.startTime - Start timestamp
|
|
48
|
+
* @param {string|null} [options.buildId] - Optional build ID
|
|
49
|
+
* @returns {Object} Server info object
|
|
50
|
+
*/
|
|
51
|
+
export function buildServerInfo({
|
|
52
|
+
port,
|
|
53
|
+
pid,
|
|
54
|
+
startTime,
|
|
55
|
+
buildId = null
|
|
56
|
+
}) {
|
|
57
|
+
let info = {
|
|
58
|
+
port: port.toString(),
|
|
59
|
+
pid,
|
|
60
|
+
startTime
|
|
61
|
+
};
|
|
62
|
+
if (buildId) {
|
|
63
|
+
info.buildId = buildId;
|
|
64
|
+
}
|
|
65
|
+
return info;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// Services Building
|
|
70
|
+
// ============================================================================
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Build services object with extras for http-server
|
|
74
|
+
* @param {Object} options - Options
|
|
75
|
+
* @param {Object} [options.services] - Base services object
|
|
76
|
+
* @param {string|null} [options.buildId] - Build ID
|
|
77
|
+
* @param {Object|null} [options.tddService] - TDD service (only in TDD mode)
|
|
78
|
+
* @returns {Object} Services object with extras
|
|
79
|
+
*/
|
|
80
|
+
export function buildServicesWithExtras({
|
|
81
|
+
services = {},
|
|
82
|
+
buildId = null,
|
|
83
|
+
tddService = null
|
|
84
|
+
}) {
|
|
85
|
+
return {
|
|
86
|
+
...services,
|
|
87
|
+
buildId,
|
|
88
|
+
tddService
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ============================================================================
|
|
93
|
+
// Client Options Building
|
|
94
|
+
// ============================================================================
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Build API client options from config
|
|
98
|
+
* @param {Object} config - Configuration object
|
|
99
|
+
* @returns {Object|null} Client options or null if no API key
|
|
100
|
+
*/
|
|
101
|
+
export function buildClientOptions(config) {
|
|
102
|
+
if (!hasApiKey(config)) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
baseUrl: config.apiUrl,
|
|
107
|
+
token: config.apiKey,
|
|
108
|
+
command: 'run'
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ============================================================================
|
|
113
|
+
// Server Interface Building
|
|
114
|
+
// ============================================================================
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Build server interface object for compatibility
|
|
118
|
+
* @param {Object} options - Options
|
|
119
|
+
* @param {Object|null} options.handler - Screenshot handler
|
|
120
|
+
* @param {Object|null} options.httpServer - HTTP server instance
|
|
121
|
+
* @returns {Object} Server interface
|
|
122
|
+
*/
|
|
123
|
+
export function buildServerInterface({
|
|
124
|
+
handler,
|
|
125
|
+
httpServer
|
|
126
|
+
}) {
|
|
127
|
+
return {
|
|
128
|
+
getScreenshotCount: buildId => handler?.getScreenshotCount?.(buildId) || 0,
|
|
129
|
+
finishBuild: buildId => httpServer?.finishBuild?.(buildId)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ============================================================================
|
|
134
|
+
// Handler Mode Determination
|
|
135
|
+
// ============================================================================
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Determine handler mode configuration
|
|
139
|
+
* @param {Object} options - Options
|
|
140
|
+
* @param {boolean} options.tddMode - Whether in TDD mode
|
|
141
|
+
* @param {Object} options.config - Configuration object
|
|
142
|
+
* @param {boolean} options.setBaseline - Whether to set baseline
|
|
143
|
+
* @returns {{ mode: 'tdd'|'api', tddConfig: Object|null, clientOptions: Object|null }}
|
|
144
|
+
*/
|
|
145
|
+
export function determineHandlerMode({
|
|
146
|
+
tddMode,
|
|
147
|
+
config,
|
|
148
|
+
setBaseline
|
|
149
|
+
}) {
|
|
150
|
+
if (tddMode) {
|
|
151
|
+
return {
|
|
152
|
+
mode: 'tdd',
|
|
153
|
+
tddConfig: {
|
|
154
|
+
config,
|
|
155
|
+
baselineBuildId: config?.baselineBuildId,
|
|
156
|
+
baselineComparisonId: config?.baselineComparisonId,
|
|
157
|
+
setBaseline
|
|
158
|
+
},
|
|
159
|
+
clientOptions: null
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
mode: 'api',
|
|
164
|
+
tddConfig: null,
|
|
165
|
+
clientOptions: buildClientOptions(config)
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ============================================================================
|
|
170
|
+
// Path Building
|
|
171
|
+
// ============================================================================
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Build server.json file path
|
|
175
|
+
* @param {string} projectRoot - Project root directory
|
|
176
|
+
* @returns {{ dir: string, file: string }}
|
|
177
|
+
*/
|
|
178
|
+
export function buildServerJsonPaths(projectRoot) {
|
|
179
|
+
return {
|
|
180
|
+
dir: `${projectRoot}/.vizzly`,
|
|
181
|
+
file: `${projectRoot}/.vizzly/server.json`
|
|
182
|
+
};
|
|
183
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Manager Module - Public exports
|
|
3
|
+
*
|
|
4
|
+
* Provides functional server management primitives:
|
|
5
|
+
* - core.js: Pure functions for building server info, configs, interfaces
|
|
6
|
+
* - operations.js: Server operations with dependency injection
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync, mkdirSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import { createApiClient } from '../api/index.js';
|
|
11
|
+
import { createApiHandler } from '../server/handlers/api-handler.js';
|
|
12
|
+
import { createTddHandler } from '../server/handlers/tdd-handler.js';
|
|
13
|
+
import { createHttpServer } from '../server/http-server.js';
|
|
14
|
+
|
|
15
|
+
// Core pure functions
|
|
16
|
+
import { buildServerInterface } from './core.js';
|
|
17
|
+
export { buildClientOptions, buildServerInfo, buildServerInterface, buildServerJsonPaths, buildServicesWithExtras, DEFAULT_PORT, determineHandlerMode, getPort, hasApiKey } from './core.js';
|
|
18
|
+
|
|
19
|
+
// Server operations (take dependencies as parameters)
|
|
20
|
+
import { getTddResults, startServer, stopServer } from './operations.js';
|
|
21
|
+
export { getTddResults, removeServerJson, startServer, stopServer, writeServerJson } from './operations.js';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create a server manager object that provides the interface commands expect.
|
|
25
|
+
* This is a thin functional wrapper that encapsulates the server lifecycle.
|
|
26
|
+
*
|
|
27
|
+
* @param {Object} config - Configuration object
|
|
28
|
+
* @param {Object} [services={}] - Optional services object
|
|
29
|
+
* @returns {Object} Server manager with start/stop/getTddResults methods
|
|
30
|
+
*/
|
|
31
|
+
export function createServerManager(config, services = {}) {
|
|
32
|
+
let httpServer = null;
|
|
33
|
+
let handler = null;
|
|
34
|
+
let deps = {
|
|
35
|
+
createHttpServer,
|
|
36
|
+
createTddHandler,
|
|
37
|
+
createApiHandler,
|
|
38
|
+
createApiClient,
|
|
39
|
+
fs: {
|
|
40
|
+
mkdirSync,
|
|
41
|
+
writeFileSync,
|
|
42
|
+
existsSync,
|
|
43
|
+
unlinkSync
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
async start(buildId, tddMode, setBaseline) {
|
|
48
|
+
let result = await startServer({
|
|
49
|
+
config,
|
|
50
|
+
buildId,
|
|
51
|
+
tddMode,
|
|
52
|
+
setBaseline,
|
|
53
|
+
projectRoot: process.cwd(),
|
|
54
|
+
services,
|
|
55
|
+
deps
|
|
56
|
+
});
|
|
57
|
+
httpServer = result.httpServer;
|
|
58
|
+
handler = result.handler;
|
|
59
|
+
},
|
|
60
|
+
async stop() {
|
|
61
|
+
await stopServer({
|
|
62
|
+
httpServer,
|
|
63
|
+
handler,
|
|
64
|
+
projectRoot: process.cwd(),
|
|
65
|
+
deps
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
async getTddResults() {
|
|
69
|
+
return getTddResults({
|
|
70
|
+
tddMode: true,
|
|
71
|
+
handler
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
get server() {
|
|
75
|
+
return buildServerInterface({
|
|
76
|
+
handler,
|
|
77
|
+
httpServer
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Manager Operations - Server operations with dependency injection
|
|
3
|
+
*
|
|
4
|
+
* Each operation takes its dependencies as parameters:
|
|
5
|
+
* - fs: filesystem operations (mkdirSync, writeFileSync, existsSync, unlinkSync)
|
|
6
|
+
* - createHttpServer: factory for HTTP server
|
|
7
|
+
* - createTddHandler: factory for TDD handler
|
|
8
|
+
* - createApiHandler: factory for API handler
|
|
9
|
+
* - createApiClient: factory for API client
|
|
10
|
+
*
|
|
11
|
+
* This makes them trivially testable without mocking modules.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { buildServerInfo, buildServerJsonPaths, buildServicesWithExtras, determineHandlerMode, getPort } from './core.js';
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Server Lifecycle Operations
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Start the screenshot server
|
|
22
|
+
* @param {Object} options - Options
|
|
23
|
+
* @param {Object} options.config - Configuration object
|
|
24
|
+
* @param {string|null} [options.buildId] - Build ID
|
|
25
|
+
* @param {boolean} [options.tddMode] - Whether in TDD mode
|
|
26
|
+
* @param {boolean} [options.setBaseline] - Whether to set baseline
|
|
27
|
+
* @param {string} options.projectRoot - Project root directory
|
|
28
|
+
* @param {Object} [options.services] - Services object
|
|
29
|
+
* @param {Object} options.deps - Dependencies
|
|
30
|
+
* @param {Function} options.deps.createHttpServer - HTTP server factory
|
|
31
|
+
* @param {Function} options.deps.createTddHandler - TDD handler factory
|
|
32
|
+
* @param {Function} options.deps.createApiHandler - API handler factory
|
|
33
|
+
* @param {Function} options.deps.createApiClient - API client factory
|
|
34
|
+
* @param {Object} options.deps.fs - Filesystem operations
|
|
35
|
+
* @returns {Promise<{ httpServer: Object, handler: Object, tddMode: boolean }>}
|
|
36
|
+
*/
|
|
37
|
+
export async function startServer({
|
|
38
|
+
config,
|
|
39
|
+
buildId = null,
|
|
40
|
+
tddMode = false,
|
|
41
|
+
setBaseline = false,
|
|
42
|
+
projectRoot,
|
|
43
|
+
services = {},
|
|
44
|
+
deps
|
|
45
|
+
}) {
|
|
46
|
+
let {
|
|
47
|
+
createHttpServer,
|
|
48
|
+
createTddHandler,
|
|
49
|
+
createApiHandler,
|
|
50
|
+
createApiClient,
|
|
51
|
+
fs
|
|
52
|
+
} = deps;
|
|
53
|
+
let port = getPort(config);
|
|
54
|
+
let handler;
|
|
55
|
+
|
|
56
|
+
// Determine which handler mode to use
|
|
57
|
+
let handlerMode = determineHandlerMode({
|
|
58
|
+
tddMode,
|
|
59
|
+
config,
|
|
60
|
+
setBaseline
|
|
61
|
+
});
|
|
62
|
+
if (handlerMode.mode === 'tdd') {
|
|
63
|
+
handler = createTddHandler(config, projectRoot, handlerMode.tddConfig.baselineBuildId, handlerMode.tddConfig.baselineComparisonId, setBaseline);
|
|
64
|
+
await handler.initialize();
|
|
65
|
+
} else {
|
|
66
|
+
let client = handlerMode.clientOptions ? createApiClient(handlerMode.clientOptions) : null;
|
|
67
|
+
handler = createApiHandler(client);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Build services with extras
|
|
71
|
+
let servicesWithExtras = buildServicesWithExtras({
|
|
72
|
+
services,
|
|
73
|
+
buildId,
|
|
74
|
+
tddService: tddMode ? handler.tddService : null
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Create and start HTTP server
|
|
78
|
+
let httpServer = createHttpServer(port, handler, servicesWithExtras);
|
|
79
|
+
if (httpServer) {
|
|
80
|
+
await httpServer.start();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Write server.json for SDK discovery
|
|
84
|
+
writeServerJson({
|
|
85
|
+
projectRoot,
|
|
86
|
+
port,
|
|
87
|
+
buildId,
|
|
88
|
+
fs
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
httpServer,
|
|
92
|
+
handler,
|
|
93
|
+
tddMode
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Stop the screenshot server
|
|
99
|
+
* @param {Object} options - Options
|
|
100
|
+
* @param {Object|null} options.httpServer - HTTP server instance
|
|
101
|
+
* @param {Object|null} options.handler - Handler instance
|
|
102
|
+
* @param {string} options.projectRoot - Project root directory
|
|
103
|
+
* @param {Object} options.deps - Dependencies
|
|
104
|
+
* @param {Object} options.deps.fs - Filesystem operations
|
|
105
|
+
* @returns {Promise<void>}
|
|
106
|
+
*/
|
|
107
|
+
export async function stopServer({
|
|
108
|
+
httpServer,
|
|
109
|
+
handler,
|
|
110
|
+
projectRoot,
|
|
111
|
+
deps
|
|
112
|
+
}) {
|
|
113
|
+
let {
|
|
114
|
+
fs
|
|
115
|
+
} = deps;
|
|
116
|
+
if (httpServer) {
|
|
117
|
+
await httpServer.stop();
|
|
118
|
+
}
|
|
119
|
+
if (handler?.cleanup) {
|
|
120
|
+
try {
|
|
121
|
+
handler.cleanup();
|
|
122
|
+
} catch {
|
|
123
|
+
// Don't throw - cleanup errors shouldn't fail the stop process
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Clean up server.json
|
|
128
|
+
removeServerJson({
|
|
129
|
+
projectRoot,
|
|
130
|
+
fs
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ============================================================================
|
|
135
|
+
// Server.json Operations
|
|
136
|
+
// ============================================================================
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Write server.json file for SDK discovery
|
|
140
|
+
* @param {Object} options - Options
|
|
141
|
+
* @param {string} options.projectRoot - Project root directory
|
|
142
|
+
* @param {number} options.port - Server port
|
|
143
|
+
* @param {string|null} [options.buildId] - Optional build ID
|
|
144
|
+
* @param {Object} options.fs - Filesystem operations
|
|
145
|
+
*/
|
|
146
|
+
export function writeServerJson({
|
|
147
|
+
projectRoot,
|
|
148
|
+
port,
|
|
149
|
+
buildId = null,
|
|
150
|
+
fs
|
|
151
|
+
}) {
|
|
152
|
+
try {
|
|
153
|
+
let paths = buildServerJsonPaths(projectRoot);
|
|
154
|
+
fs.mkdirSync(paths.dir, {
|
|
155
|
+
recursive: true
|
|
156
|
+
});
|
|
157
|
+
let serverInfo = buildServerInfo({
|
|
158
|
+
port,
|
|
159
|
+
pid: process.pid,
|
|
160
|
+
startTime: Date.now(),
|
|
161
|
+
buildId
|
|
162
|
+
});
|
|
163
|
+
fs.writeFileSync(paths.file, JSON.stringify(serverInfo, null, 2));
|
|
164
|
+
} catch {
|
|
165
|
+
// Non-fatal - SDK can still use health check or environment variables
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Remove server.json file
|
|
171
|
+
* @param {Object} options - Options
|
|
172
|
+
* @param {string} options.projectRoot - Project root directory
|
|
173
|
+
* @param {Object} options.fs - Filesystem operations
|
|
174
|
+
*/
|
|
175
|
+
export function removeServerJson({
|
|
176
|
+
projectRoot,
|
|
177
|
+
fs
|
|
178
|
+
}) {
|
|
179
|
+
try {
|
|
180
|
+
let paths = buildServerJsonPaths(projectRoot);
|
|
181
|
+
if (fs.existsSync(paths.file)) {
|
|
182
|
+
fs.unlinkSync(paths.file);
|
|
183
|
+
}
|
|
184
|
+
} catch {
|
|
185
|
+
// Non-fatal - cleanup errors shouldn't fail the stop process
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// ============================================================================
|
|
190
|
+
// TDD Results
|
|
191
|
+
// ============================================================================
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get TDD results from handler
|
|
195
|
+
* @param {Object} options - Options
|
|
196
|
+
* @param {boolean} options.tddMode - Whether in TDD mode
|
|
197
|
+
* @param {Object|null} options.handler - Handler instance
|
|
198
|
+
* @returns {Promise<Object|null>} TDD results or null
|
|
199
|
+
*/
|
|
200
|
+
export async function getTddResults({
|
|
201
|
+
tddMode,
|
|
202
|
+
handler
|
|
203
|
+
}) {
|
|
204
|
+
if (!tddMode || !handler?.getResults) {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
return await handler.getResults();
|
|
208
|
+
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Build Manager
|
|
3
|
-
* Manages the build lifecycle and coordinates test execution
|
|
2
|
+
* Build Manager - Pure functions for build lifecycle management
|
|
4
3
|
*/
|
|
5
4
|
|
|
6
5
|
import crypto from 'node:crypto';
|
|
7
|
-
import { VizzlyError } from '../errors/vizzly-error.js';
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
8
|
* Generate unique build ID for local build management only.
|
|
@@ -108,7 +106,7 @@ export function createQueuedBuild(buildOptions) {
|
|
|
108
106
|
* @returns {Object} Validation result
|
|
109
107
|
*/
|
|
110
108
|
export function validateBuildOptions(buildOptions) {
|
|
111
|
-
|
|
109
|
+
let errors = [];
|
|
112
110
|
if (!buildOptions.name && !buildOptions.branch) {
|
|
113
111
|
errors.push('Either name or branch is required');
|
|
114
112
|
}
|
|
@@ -119,69 +117,4 @@ export function validateBuildOptions(buildOptions) {
|
|
|
119
117
|
valid: errors.length === 0,
|
|
120
118
|
errors
|
|
121
119
|
};
|
|
122
|
-
}
|
|
123
|
-
export class BuildManager {
|
|
124
|
-
constructor(config) {
|
|
125
|
-
this.config = config;
|
|
126
|
-
this.currentBuild = null;
|
|
127
|
-
this.buildQueue = [];
|
|
128
|
-
}
|
|
129
|
-
async createBuild(buildOptions) {
|
|
130
|
-
const build = createBuildObject(buildOptions);
|
|
131
|
-
this.currentBuild = build;
|
|
132
|
-
return build;
|
|
133
|
-
}
|
|
134
|
-
async updateBuildStatus(buildId, status, updates = {}) {
|
|
135
|
-
if (!this.currentBuild || this.currentBuild.id !== buildId) {
|
|
136
|
-
throw new VizzlyError(`Build ${buildId} not found`, 'BUILD_NOT_FOUND');
|
|
137
|
-
}
|
|
138
|
-
this.currentBuild = updateBuild(this.currentBuild, status, updates);
|
|
139
|
-
return this.currentBuild;
|
|
140
|
-
}
|
|
141
|
-
async addScreenshot(buildId, screenshot) {
|
|
142
|
-
if (!this.currentBuild || this.currentBuild.id !== buildId) {
|
|
143
|
-
throw new VizzlyError(`Build ${buildId} not found`, 'BUILD_NOT_FOUND');
|
|
144
|
-
}
|
|
145
|
-
this.currentBuild = addScreenshotToBuild(this.currentBuild, screenshot);
|
|
146
|
-
return this.currentBuild;
|
|
147
|
-
}
|
|
148
|
-
async finalizeBuild(buildId, result = {}) {
|
|
149
|
-
if (!this.currentBuild || this.currentBuild.id !== buildId) {
|
|
150
|
-
throw new VizzlyError(`Build ${buildId} not found`, 'BUILD_NOT_FOUND');
|
|
151
|
-
}
|
|
152
|
-
this.currentBuild = finalizeBuildObject(this.currentBuild, result);
|
|
153
|
-
return this.currentBuild;
|
|
154
|
-
}
|
|
155
|
-
getCurrentBuild() {
|
|
156
|
-
return this.currentBuild;
|
|
157
|
-
}
|
|
158
|
-
queueBuild(buildOptions) {
|
|
159
|
-
const queuedBuild = createQueuedBuild(buildOptions);
|
|
160
|
-
this.buildQueue.push(queuedBuild);
|
|
161
|
-
}
|
|
162
|
-
async clear() {
|
|
163
|
-
// Cancel pending build if exists
|
|
164
|
-
if (this.currentBuild && this.currentBuild.status === 'pending') {
|
|
165
|
-
await this.updateBuildStatus(this.currentBuild.id, 'cancelled');
|
|
166
|
-
}
|
|
167
|
-
this.buildQueue.length = 0;
|
|
168
|
-
this.currentBuild = null;
|
|
169
|
-
}
|
|
170
|
-
async processNextBuild() {
|
|
171
|
-
if (this.buildQueue.length === 0) {
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
const buildOptions = this.buildQueue.shift();
|
|
175
|
-
return await this.createBuild(buildOptions);
|
|
176
|
-
}
|
|
177
|
-
getQueueStatus() {
|
|
178
|
-
return {
|
|
179
|
-
length: this.buildQueue.length,
|
|
180
|
-
items: this.buildQueue.map(item => ({
|
|
181
|
-
name: item.name,
|
|
182
|
-
branch: item.branch,
|
|
183
|
-
queuedAt: item.queuedAt
|
|
184
|
-
}))
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
120
|
}
|
package/dist/services/index.js
CHANGED
|
@@ -1,64 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Service Factory
|
|
3
|
-
* Creates
|
|
3
|
+
* Creates services for plugin API compatibility.
|
|
4
|
+
*
|
|
5
|
+
* Internal commands now use functional modules directly:
|
|
6
|
+
* - API: import { createApiClient, getBuild } from '../api/index.js'
|
|
7
|
+
* - Auth: import { createAuthClient, whoami } from '../auth/index.js'
|
|
8
|
+
*
|
|
9
|
+
* This factory is only used by cli.js to provide services to plugins.
|
|
4
10
|
*/
|
|
5
11
|
|
|
6
|
-
import { ApiService } from './api-service.js';
|
|
7
|
-
import { AuthService } from './auth-service.js';
|
|
8
|
-
import { BuildManager } from './build-manager.js';
|
|
9
|
-
import { ConfigService } from './config-service.js';
|
|
10
|
-
import { ProjectService } from './project-service.js';
|
|
11
12
|
import { ServerManager } from './server-manager.js';
|
|
12
|
-
import { createTDDService } from './tdd-service.js';
|
|
13
13
|
import { TestRunner } from './test-runner.js';
|
|
14
|
-
import { createUploader } from './uploader.js';
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
|
-
* Create
|
|
16
|
+
* Create services for plugin API compatibility.
|
|
17
|
+
*
|
|
18
|
+
* Only creates services that plugins actually need:
|
|
19
|
+
* - testRunner: Build lifecycle management with EventEmitter
|
|
20
|
+
* - serverManager: Screenshot server control
|
|
21
|
+
*
|
|
22
|
+
* Commands use functional modules directly - this factory exists
|
|
23
|
+
* only to support the plugin API contract.
|
|
24
|
+
*
|
|
18
25
|
* @param {Object} config - Configuration object
|
|
19
|
-
* @
|
|
20
|
-
* @returns {Object} Services object
|
|
26
|
+
* @returns {Object} Services object for plugins
|
|
21
27
|
*/
|
|
22
|
-
export function createServices(config
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
allowNoToken: true
|
|
28
|
+
export function createServices(config) {
|
|
29
|
+
let serverManager = new ServerManager(config, {
|
|
30
|
+
services: {}
|
|
26
31
|
});
|
|
27
|
-
|
|
28
|
-
baseUrl: config.apiUrl
|
|
29
|
-
});
|
|
30
|
-
const configService = new ConfigService(config, {
|
|
31
|
-
projectRoot: process.cwd()
|
|
32
|
-
});
|
|
33
|
-
const projectService = new ProjectService(config, {
|
|
34
|
-
apiService,
|
|
35
|
-
authService
|
|
36
|
-
});
|
|
37
|
-
const uploader = createUploader({
|
|
38
|
-
...config,
|
|
39
|
-
command
|
|
40
|
-
});
|
|
41
|
-
const buildManager = new BuildManager(config);
|
|
42
|
-
const tddService = createTDDService(config, {
|
|
43
|
-
authService
|
|
44
|
-
});
|
|
45
|
-
const serverManager = new ServerManager(config, {
|
|
46
|
-
services: {
|
|
47
|
-
configService,
|
|
48
|
-
authService,
|
|
49
|
-
projectService
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
const testRunner = new TestRunner(config, buildManager, serverManager, tddService);
|
|
32
|
+
let testRunner = new TestRunner(config, serverManager);
|
|
53
33
|
return {
|
|
54
|
-
apiService,
|
|
55
|
-
authService,
|
|
56
|
-
configService,
|
|
57
|
-
projectService,
|
|
58
|
-
uploader,
|
|
59
|
-
buildManager,
|
|
60
34
|
serverManager,
|
|
61
|
-
tddService,
|
|
62
35
|
testRunner
|
|
63
36
|
};
|
|
64
37
|
}
|