uloop-cli 0.64.0 → 0.64.1
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/cli.bundle.cjs +2 -2
- package/dist/cli.bundle.cjs.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/cli-e2e.test.ts +147 -3
- package/src/default-tools.json +1 -1
- package/src/version.ts +1 -1
package/package.json
CHANGED
|
@@ -7,7 +7,12 @@
|
|
|
7
7
|
* @jest-environment node
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
execSync,
|
|
12
|
+
ExecSyncOptionsWithStringEncoding,
|
|
13
|
+
spawnSync,
|
|
14
|
+
SpawnSyncOptionsWithStringEncoding,
|
|
15
|
+
} from 'child_process';
|
|
11
16
|
import { join } from 'path';
|
|
12
17
|
|
|
13
18
|
const CLI_PATH = join(__dirname, '../..', 'dist/cli.bundle.cjs');
|
|
@@ -21,6 +26,13 @@ const EXEC_OPTIONS: ExecSyncOptionsWithStringEncoding = {
|
|
|
21
26
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
22
27
|
};
|
|
23
28
|
|
|
29
|
+
const SPAWN_OPTIONS: SpawnSyncOptionsWithStringEncoding = {
|
|
30
|
+
encoding: 'utf-8',
|
|
31
|
+
timeout: 60000,
|
|
32
|
+
cwd: UNITY_PROJECT_ROOT,
|
|
33
|
+
stdio: 'pipe',
|
|
34
|
+
};
|
|
35
|
+
|
|
24
36
|
const INTERVAL_MS = 1500;
|
|
25
37
|
const DOMAIN_RELOAD_RETRY_MS = 3000;
|
|
26
38
|
const DOMAIN_RELOAD_MAX_RETRIES = 3;
|
|
@@ -54,6 +66,15 @@ function runCli(args: string): { stdout: string; stderr: string; exitCode: numbe
|
|
|
54
66
|
}
|
|
55
67
|
}
|
|
56
68
|
|
|
69
|
+
function runCliParts(args: string[]): { stdout: string; stderr: string; exitCode: number } {
|
|
70
|
+
const result = spawnSync('node', [CLI_PATH, ...args], SPAWN_OPTIONS);
|
|
71
|
+
return {
|
|
72
|
+
stdout: result.stdout ?? '',
|
|
73
|
+
stderr: result.stderr ?? '',
|
|
74
|
+
exitCode: result.status ?? 1,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
57
78
|
function runCliWithRetry(args: string): { stdout: string; stderr: string; exitCode: number } {
|
|
58
79
|
for (let attempt = 0; attempt < DOMAIN_RELOAD_MAX_RETRIES; attempt++) {
|
|
59
80
|
const result = runCli(args);
|
|
@@ -72,12 +93,44 @@ function runCliWithRetry(args: string): { stdout: string; stderr: string; exitCo
|
|
|
72
93
|
return runCli(args);
|
|
73
94
|
}
|
|
74
95
|
|
|
96
|
+
function runCliWithRetryParts(args: string[]): {
|
|
97
|
+
stdout: string;
|
|
98
|
+
stderr: string;
|
|
99
|
+
exitCode: number;
|
|
100
|
+
} {
|
|
101
|
+
for (let attempt = 0; attempt < DOMAIN_RELOAD_MAX_RETRIES; attempt++) {
|
|
102
|
+
const result = runCliParts(args);
|
|
103
|
+
const output = result.stderr || result.stdout;
|
|
104
|
+
|
|
105
|
+
if (result.exitCode === 0 || !isDomainReloadError(output)) {
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (attempt < DOMAIN_RELOAD_MAX_RETRIES - 1) {
|
|
110
|
+
sleepSync(DOMAIN_RELOAD_RETRY_MS);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return runCliParts(args);
|
|
115
|
+
}
|
|
116
|
+
|
|
75
117
|
function runCliJson<T>(args: string): T {
|
|
76
118
|
const { stdout, stderr, exitCode } = runCliWithRetry(args);
|
|
77
119
|
if (exitCode !== 0) {
|
|
78
120
|
throw new Error(`CLI failed with exit code ${exitCode}: ${stderr || stdout}`);
|
|
79
121
|
}
|
|
80
|
-
|
|
122
|
+
|
|
123
|
+
const trimmedOutput = stdout.trim();
|
|
124
|
+
const jsonStartByLine = trimmedOutput.lastIndexOf('\n{');
|
|
125
|
+
const jsonStart = jsonStartByLine >= 0 ? jsonStartByLine + 1 : trimmedOutput.indexOf('{');
|
|
126
|
+
const jsonEnd = trimmedOutput.lastIndexOf('}');
|
|
127
|
+
|
|
128
|
+
if (jsonStart < 0 || jsonEnd < 0 || jsonEnd < jsonStart) {
|
|
129
|
+
throw new Error(`JSON payload not found in CLI output: ${trimmedOutput}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const jsonPayload = trimmedOutput.slice(jsonStart, jsonEnd + 1);
|
|
133
|
+
return JSON.parse(jsonPayload) as T;
|
|
81
134
|
}
|
|
82
135
|
|
|
83
136
|
describe('CLI E2E Tests (requires running Unity)', () => {
|
|
@@ -97,6 +150,7 @@ describe('CLI E2E Tests (requires running Unity)', () => {
|
|
|
97
150
|
describe('get-logs', () => {
|
|
98
151
|
const TEST_LOG_MENU_PATH = 'uLoopMCP/Debug/LogGetter Tests/Output Test Logs';
|
|
99
152
|
const MENU_ITEM_WAIT_MS = 1000;
|
|
153
|
+
const ERROR_FAMILY_PREFIX = 'CliE2EErrorFamily';
|
|
100
154
|
|
|
101
155
|
function setupTestLogs(): void {
|
|
102
156
|
runCliWithRetry('clear-console');
|
|
@@ -107,6 +161,38 @@ describe('CLI E2E Tests (requires running Unity)', () => {
|
|
|
107
161
|
sleepSync(MENU_ITEM_WAIT_MS);
|
|
108
162
|
}
|
|
109
163
|
|
|
164
|
+
function setupErrorFamilyLogs(token: string): void {
|
|
165
|
+
runCliWithRetry('clear-console');
|
|
166
|
+
const code = [
|
|
167
|
+
'using UnityEngine;',
|
|
168
|
+
'using System;',
|
|
169
|
+
`Debug.LogError("${ERROR_FAMILY_PREFIX}_Error_${token}");`,
|
|
170
|
+
`Debug.LogException(new InvalidOperationException("${ERROR_FAMILY_PREFIX}_Exception_${token}"));`,
|
|
171
|
+
`Debug.LogAssertion("${ERROR_FAMILY_PREFIX}_Assert_${token}");`,
|
|
172
|
+
`Debug.LogWarning("${ERROR_FAMILY_PREFIX}_Warning_${token}");`,
|
|
173
|
+
].join(' ');
|
|
174
|
+
const result = runCliWithRetryParts(['execute-dynamic-code', '--code', code]);
|
|
175
|
+
if (result.exitCode !== 0) {
|
|
176
|
+
throw new Error(`execute-dynamic-code failed: ${result.stderr || result.stdout}`);
|
|
177
|
+
}
|
|
178
|
+
sleepSync(MENU_ITEM_WAIT_MS);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function setupAssertTextLogs(token: string): void {
|
|
182
|
+
runCliWithRetry('clear-console');
|
|
183
|
+
const code = [
|
|
184
|
+
'using UnityEngine;',
|
|
185
|
+
`Debug.Log("Please assert your identity ${token}");`,
|
|
186
|
+
`Debug.LogWarning("All assertions passed ${token}");`,
|
|
187
|
+
`Debug.LogError("${ERROR_FAMILY_PREFIX}_ErrorOnly_${token}");`,
|
|
188
|
+
].join(' ');
|
|
189
|
+
const result = runCliWithRetryParts(['execute-dynamic-code', '--code', code]);
|
|
190
|
+
if (result.exitCode !== 0) {
|
|
191
|
+
throw new Error(`execute-dynamic-code failed: ${result.stderr || result.stdout}`);
|
|
192
|
+
}
|
|
193
|
+
sleepSync(MENU_ITEM_WAIT_MS);
|
|
194
|
+
}
|
|
195
|
+
|
|
110
196
|
it('should retrieve test logs after executing Output Test Logs menu item', () => {
|
|
111
197
|
setupTestLogs();
|
|
112
198
|
|
|
@@ -163,6 +249,64 @@ describe('CLI E2E Tests (requires running Unity)', () => {
|
|
|
163
249
|
expect(messages.some((m) => m.includes('This is an error log'))).toBe(true);
|
|
164
250
|
});
|
|
165
251
|
|
|
252
|
+
it('should filter by lowercase log type error', () => {
|
|
253
|
+
setupTestLogs();
|
|
254
|
+
|
|
255
|
+
const result = runCliJson<{ Logs: Array<{ Type: string; Message: string }> }>(
|
|
256
|
+
'get-logs --log-type error',
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
expect(result.Logs.length).toBeGreaterThan(0);
|
|
260
|
+
for (const log of result.Logs) {
|
|
261
|
+
expect(log.Type).toBe('Error');
|
|
262
|
+
}
|
|
263
|
+
const messages = result.Logs.map((log) => log.Message);
|
|
264
|
+
expect(messages.some((m) => m.includes('This is an error log'))).toBe(true);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should include error and exception logs in Error filter', () => {
|
|
268
|
+
const token = `${Date.now()}`;
|
|
269
|
+
setupErrorFamilyLogs(token);
|
|
270
|
+
|
|
271
|
+
const result = runCliJson<{ Logs: Array<{ Type: string; Message: string }> }>(
|
|
272
|
+
`get-logs --log-type Error --search-text "${token}" --max-count 20`,
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
expect(result.Logs.length).toBeGreaterThanOrEqual(2);
|
|
276
|
+
for (const log of result.Logs) {
|
|
277
|
+
expect(log.Type).toBe('Error');
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const messages = result.Logs.map((log) => log.Message);
|
|
281
|
+
expect(messages.some((m) => m.includes(`${ERROR_FAMILY_PREFIX}_Error_${token}`))).toBe(true);
|
|
282
|
+
expect(messages.some((m) => m.includes(`${ERROR_FAMILY_PREFIX}_Exception_${token}`))).toBe(
|
|
283
|
+
true,
|
|
284
|
+
);
|
|
285
|
+
expect(messages.some((m) => m.includes(`${ERROR_FAMILY_PREFIX}_Warning_${token}`))).toBe(
|
|
286
|
+
false,
|
|
287
|
+
);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('should not include plain assert text logs in Error filter', () => {
|
|
291
|
+
const token = `${Date.now()}`;
|
|
292
|
+
setupAssertTextLogs(token);
|
|
293
|
+
|
|
294
|
+
const result = runCliJson<{ Logs: Array<{ Type: string; Message: string }> }>(
|
|
295
|
+
`get-logs --log-type Error --search-text "${token}" --max-count 20`,
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
for (const log of result.Logs) {
|
|
299
|
+
expect(log.Type).toBe('Error');
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const messages = result.Logs.map((log) => log.Message);
|
|
303
|
+
expect(messages.some((m) => m.includes(`${ERROR_FAMILY_PREFIX}_ErrorOnly_${token}`))).toBe(
|
|
304
|
+
true,
|
|
305
|
+
);
|
|
306
|
+
expect(messages.some((m) => m.includes(`Please assert your identity ${token}`))).toBe(false);
|
|
307
|
+
expect(messages.some((m) => m.includes(`All assertions passed ${token}`))).toBe(false);
|
|
308
|
+
});
|
|
309
|
+
|
|
166
310
|
it('should search logs by text', () => {
|
|
167
311
|
setupTestLogs();
|
|
168
312
|
|
|
@@ -487,7 +631,7 @@ describe('CLI E2E Tests (requires running Unity)', () => {
|
|
|
487
631
|
const { stdout, exitCode } = runCli('launch --help');
|
|
488
632
|
|
|
489
633
|
expect(exitCode).toBe(0);
|
|
490
|
-
expect(stdout).toContain('
|
|
634
|
+
expect(stdout).toContain('Open a Unity project');
|
|
491
635
|
expect(stdout).toContain('--restart');
|
|
492
636
|
expect(stdout).toContain('--platform');
|
|
493
637
|
expect(stdout).toContain('--max-depth');
|
package/src/default-tools.json
CHANGED
package/src/version.ts
CHANGED
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* This file exists to avoid bundling the entire package.json into the CLI bundle.
|
|
5
5
|
* This version is automatically updated by release-please.
|
|
6
6
|
*/
|
|
7
|
-
export const VERSION = '0.64.
|
|
7
|
+
export const VERSION = '0.64.1'; // x-release-please-version
|