@rage-against-the-pixel/unity-cli 3.0.1 → 4.0.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.
Files changed (60) hide show
  1. package/README.md +89 -223
  2. package/dist/android-sdk.js +8 -1
  3. package/dist/android-sdk.js.map +1 -1
  4. package/dist/cli.js +195 -506
  5. package/dist/cli.js.map +1 -1
  6. package/dist/failure-markers.d.ts +17 -0
  7. package/dist/failure-markers.js +46 -0
  8. package/dist/failure-markers.js.map +1 -0
  9. package/dist/github-actions-ci.d.ts +1 -0
  10. package/dist/github-actions-ci.js +17 -3
  11. package/dist/github-actions-ci.js.map +1 -1
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.js +2 -2
  14. package/dist/index.js.map +1 -1
  15. package/dist/license-client.d.ts +113 -2
  16. package/dist/license-client.js +715 -54
  17. package/dist/license-client.js.map +1 -1
  18. package/dist/logger-provider.d.ts +2 -0
  19. package/dist/logger-provider.js +3 -0
  20. package/dist/logger-provider.js.map +1 -1
  21. package/dist/logging.d.ts +6 -1
  22. package/dist/logging.js +66 -5
  23. package/dist/logging.js.map +1 -1
  24. package/dist/process-tracker.d.ts +71 -0
  25. package/dist/process-tracker.js +213 -0
  26. package/dist/process-tracker.js.map +1 -0
  27. package/dist/unity-cli.d.ts +97 -0
  28. package/dist/unity-cli.js +587 -0
  29. package/dist/unity-cli.js.map +1 -0
  30. package/dist/unity-editor.d.ts +25 -16
  31. package/dist/unity-editor.js +204 -107
  32. package/dist/unity-editor.js.map +1 -1
  33. package/dist/unity-installer.d.ts +134 -0
  34. package/dist/unity-installer.js +963 -0
  35. package/dist/unity-installer.js.map +1 -0
  36. package/dist/unity-logging.d.ts +16 -1
  37. package/dist/unity-logging.js +79 -40
  38. package/dist/unity-logging.js.map +1 -1
  39. package/dist/unity-project.d.ts +15 -0
  40. package/dist/unity-project.js +80 -0
  41. package/dist/unity-project.js.map +1 -1
  42. package/dist/unity-version.d.ts +4 -0
  43. package/dist/unity-version.js +40 -2
  44. package/dist/unity-version.js.map +1 -1
  45. package/dist/upm-cli.d.ts +8 -8
  46. package/dist/upm-cli.js +8 -8
  47. package/dist/upm-cli.js.map +1 -1
  48. package/dist/utilities.d.ts +27 -7
  49. package/dist/utilities.js +119 -63
  50. package/dist/utilities.js.map +1 -1
  51. package/dist/utp-benign.d.ts +13 -0
  52. package/dist/utp-benign.js +41 -0
  53. package/dist/utp-benign.js.map +1 -0
  54. package/dist/utp.d.ts +11 -2
  55. package/dist/utp.js +40 -3
  56. package/dist/utp.js.map +1 -1
  57. package/package.json +14 -15
  58. package/dist/unity-hub.d.ts +0 -127
  59. package/dist/unity-hub.js +0 -1327
  60. package/dist/unity-hub.js.map +0 -1
package/dist/cli.js CHANGED
@@ -40,101 +40,33 @@ Object.defineProperty(exports, "__esModule", { value: true });
40
40
  require("source-map-support/register");
41
41
  const fs = __importStar(require("fs"));
42
42
  const os = __importStar(require("os"));
43
- const tar = __importStar(require("tar"));
44
43
  const path = __importStar(require("path"));
45
44
  const commander_1 = require("commander");
46
- const unity_hub_1 = require("./unity-hub");
47
- const unity_editor_1 = require("./unity-editor");
48
45
  const update_notifier_1 = __importDefault(require("update-notifier"));
49
46
  const logging_1 = require("./logging");
47
+ const unity_cli_1 = require("./unity-cli");
48
+ const unity_editor_1 = require("./unity-editor");
49
+ const unity_installer_1 = require("./unity-installer");
50
50
  const unity_version_1 = require("./unity-version");
51
51
  const unity_project_1 = require("./unity-project");
52
- const child_process_1 = require("child_process");
53
52
  const android_sdk_1 = require("./android-sdk");
54
53
  const license_client_1 = require("./license-client");
55
54
  const utilities_1 = require("./utilities");
56
55
  const upm_cli_1 = require("./upm-cli");
56
+ const failure_markers_1 = require("./failure-markers");
57
57
  const pkgPath = path.join(__dirname, '..', 'package.json');
58
58
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
59
59
  (0, update_notifier_1.default)({ pkg }).notify();
60
60
  const program = new commander_1.Command();
61
61
  program.name('unity-cli')
62
- .description('A powerful all-in-one command line utility for the Unity Game Engine.')
63
- .version(pkg.version);
64
- program.command('install-all-tools')
65
- .description('Install the Unity Hub and the Unity Package Manager cli (pack/sign). Runs hub-install and upm-install in parallel.')
66
- .option('--verbose', 'Enable verbose logging.')
67
- .option('--auto-update', 'If any tools are installed, they\'re automatically updated to the latest versions. Cannot be used with --hub-version or --upm-version.')
68
- .option('--hub-version <version>', 'Specify to install a specific version of Unity Hub. Cannot be used with --auto-update.')
69
- .option('--upm-version <version>', 'Specify to install a specific version of the Unity Package Manager cli. Cannot be used with --auto-update.')
70
- .option('--json', 'Print hub path, UPM CLI version, and resolved UPM CLI path as JSON.')
71
- .action(async (options) => {
72
- if (options.verbose) {
73
- logging_1.Logger.instance.logLevel = logging_1.LogLevel.DEBUG;
74
- }
75
- logging_1.Logger.instance.debugOptions(options);
76
- if (options.autoUpdate === true && options.hubVersion) {
77
- logging_1.Logger.instance.error('Cannot use --auto-update with --hub-version.');
78
- process.exit(1);
79
- }
80
- if (options.autoUpdate === true && options.upmVersion) {
81
- logging_1.Logger.instance.error('Cannot use --auto-update with --upm-version.');
82
- process.exit(1);
83
- }
84
- try {
85
- const unityHub = new unity_hub_1.UnityHub();
86
- const upm = new upm_cli_1.UpmCli();
87
- let upmRequestedVersion = options.upmVersion?.toString()?.trim();
88
- if (options.autoUpdate === true) {
89
- const currentVersion = upm.GetInstalledReleaseTag();
90
- const latestVersion = await upm.GetLatestReleaseTag();
91
- if (currentVersion && !upm.IsUpdateAvailable(latestVersion)) {
92
- logging_1.Logger.instance.info(`Upm cli is already up to date (${currentVersion}).`);
93
- upmRequestedVersion = currentVersion;
94
- }
95
- else {
96
- if (currentVersion) {
97
- logging_1.Logger.instance.info(`Updating upm cli ${currentVersion} -> ${latestVersion}...`);
98
- }
99
- upmRequestedVersion = latestVersion;
100
- }
101
- }
102
- const [hubPath, upmVer] = await Promise.all([
103
- unityHub.Install(options.autoUpdate === true, options.hubVersion),
104
- upm.Install({
105
- version: upmRequestedVersion,
106
- skipIfInstalled: true
107
- }),
108
- ]);
109
- logging_1.Logger.instance.CI_setEnvironmentVariable('UNITY_HUB_PATH', hubPath);
110
- let upmCliPath;
111
- try {
112
- await upm.Version(upmVer);
113
- upmCliPath = upm.executable;
114
- }
115
- catch (verifyError) {
116
- logging_1.Logger.instance.warn(`Upm cli version check failed after install: ${verifyError}`);
117
- if (process.env.CI === 'true') {
118
- logging_1.Logger.instance.error('Failing in CI because the installed UPM CLI did not match the expected release.');
119
- process.exit(1);
120
- }
121
- upmCliPath = upm.ResolveManagedPrimaryPath();
122
- }
123
- if (options.json) {
124
- process.stdout.write(`\n${JSON.stringify({
125
- UNITY_HUB_PATH: hubPath,
126
- UPM_VERSION: upmVer,
127
- UPM_CLI_PATH: upmCliPath,
128
- })}\n`);
129
- }
130
- else {
131
- process.stdout.write(`Unity Hub: ${hubPath}\nUpm cli: ${upmVer}\n${upmCliPath ?? ''}\n`);
132
- }
133
- process.exit(0);
134
- }
135
- catch (error) {
136
- logging_1.Logger.instance.error(`${error}`);
137
- process.exit(1);
62
+ .description('Bridges the gaps in the official Unity CLI (unity) for CI: Unity ID licensing, Unity 4.x and 5.x editors, Android SDK setup and Editor log annotations.')
63
+ .version(pkg.version)
64
+ .option('--unity-cli-version <version>', 'The official Unity CLI version to use (e.g. 1.0.0-beta.14). Defaults to the UNITY_CLI_VERSION environment variable, then the latest release. Commands install it on first use.')
65
+ .hook('preAction', (command) => {
66
+ const version = command.opts().unityCliVersion?.toString()?.trim();
67
+ if (version) {
68
+ // every command resolves the official CLI through UnityCli.Get(), which reads the request from here
69
+ process.env.UNITY_CLI_VERSION = version;
138
70
  }
139
71
  });
140
72
  program.commandsGroup('Auth:');
@@ -146,51 +78,49 @@ program.command('license-version')
146
78
  process.exit(0);
147
79
  });
148
80
  program.command('activate-license')
149
- .description('Activate a Unity license.')
81
+ .description('Activate a Unity license. Tries the official Unity CLI first, then the Unity Licensing Client with your Unity ID email and password.')
150
82
  .option('-l, --license <license>', 'License type (personal, professional, floating). Required.')
151
- .option('-e, --email <email>', 'Email associated with the Unity account. Required when activating a personal or professional license.')
152
- .option('-p, --password <password>', 'Password for the Unity account. Required when activating a personal or professional license.')
153
- .option('-s, --serial <serial>', 'License serial number. Required when activating a professional license.')
83
+ .option('-e, --email <email>', 'Email associated with the Unity account. Used when the Unity CLI cannot activate a personal or professional license. Defaults to the UNITY_USERNAME environment variable.')
84
+ .option('-p, --password <password>', 'Password for the Unity account. Used when the Unity CLI cannot activate a personal or professional license. Defaults to the UNITY_PASSWORD environment variable, which keeps it off the command line.')
85
+ .option('-s, --serial <serial>', 'License serial number. Required when activating a professional license. Defaults to the UNITY_SERIAL environment variable.')
154
86
  .option('-c, --config <config>', 'Path to the configuration file, raw JSON, or base64 encoded JSON string. Required when activating a floating license.')
87
+ .option('-f, --license-file <licenseFile>', 'A cached license file (Unity_lic.ulf) from an earlier activation on a machine with the same identity: a path, the raw XML, or base64. Defaults to the UNITY_LICENSE environment variable. Falls back to the email and password when it cannot be used.')
155
88
  .option('--verbose', 'Enable verbose logging.')
156
89
  .option('--json', 'Prints the last line of output as JSON string.')
157
90
  .action(async (options) => {
158
91
  if (options.verbose) {
159
92
  logging_1.Logger.instance.logLevel = logging_1.LogLevel.DEBUG;
160
93
  }
94
+ // environment variables keep credentials out of the process command line
95
+ options.email ??= process.env.UNITY_USERNAME || undefined;
96
+ options.password ??= process.env.UNITY_PASSWORD || undefined;
97
+ options.serial ??= process.env.UNITY_SERIAL || undefined;
98
+ // Mask credentials in CI environments before any potential logging
99
+ logging_1.Logger.instance.maskCredential(options.email);
100
+ logging_1.Logger.instance.maskCredential(options.password);
101
+ logging_1.Logger.instance.maskCredential(options.serial);
161
102
  logging_1.Logger.instance.debugOptions(options);
162
- const client = new license_client_1.LicensingClient();
163
103
  const licenseStr = options.license?.toString()?.trim();
164
104
  if (!licenseStr || licenseStr.length === 0) {
165
105
  logging_1.Logger.instance.error('License type is required. Use -l or --license to specify it.');
166
106
  process.exit(1);
167
107
  }
168
- const licenseType = options.license.toLowerCase();
108
+ const licenseType = licenseStr.toLowerCase();
169
109
  if (![license_client_1.LicenseType.personal, license_client_1.LicenseType.professional, license_client_1.LicenseType.floating].includes(licenseType)) {
170
110
  logging_1.Logger.instance.error(`Invalid license type: ${licenseType}`);
171
111
  process.exit(1);
172
112
  }
173
- if (licenseType !== license_client_1.LicenseType.floating) {
174
- if (!options.email) {
175
- options.email = await (0, utilities_1.PromptForSecretInput)('Email: ');
176
- }
177
- if (!options.password) {
178
- options.password = await (0, utilities_1.PromptForSecretInput)('Password: ');
179
- }
180
- if (licenseType === license_client_1.LicenseType.professional && !options.serial) {
181
- options.serial = await (0, utilities_1.PromptForSecretInput)('Serial: ');
182
- }
183
- // Mask credentials in CI environments before any potential logging
184
- logging_1.Logger.instance.maskCredential(options.email);
185
- logging_1.Logger.instance.maskCredential(options.password);
113
+ if (licenseType === license_client_1.LicenseType.professional && !options.serial) {
114
+ options.serial = await (0, utilities_1.PromptForSecretInput)('Serial: ');
186
115
  logging_1.Logger.instance.maskCredential(options.serial);
187
116
  }
188
- const token = await client.Activate({
117
+ const token = await (0, license_client_1.ActivateLicense)({
189
118
  licenseType,
190
119
  servicesConfig: options.config,
191
120
  serial: options.serial,
192
121
  username: options.email,
193
- password: options.password
122
+ password: options.password,
123
+ ...(options.licenseFile ? { licenseFile: options.licenseFile } : {}),
194
124
  });
195
125
  if (licenseType === license_client_1.LicenseType.floating && token && options.json) {
196
126
  process.stdout.write(`\n${JSON.stringify({ token: token })}\n`);
@@ -198,16 +128,24 @@ program.command('activate-license')
198
128
  process.exit(0);
199
129
  });
200
130
  program.command('return-license')
201
- .description('Return a Unity license.')
131
+ .description('Return a Unity license. Tries the official Unity CLI first, then the Unity Licensing Client.')
202
132
  .option('-l, --license <license>', 'License type (personal, professional, floating)')
203
- .option('-t, --token <token>', 'Floating license token. Required when returning a floating license.')
133
+ .option('-t, --token <token>', 'Floating license token from activation. When given, the floating license is returned with the Unity Licensing Client.')
134
+ .option('--when <when>', 'auto, always or never. auto skips returning a personal or professional license on GitHub-hosted macOS and Linux runners, which share one machine identity: a return there revokes the license for every job and repo on that identity. Defaults to auto.', 'auto')
204
135
  .option('--verbose', 'Enable verbose logging.')
205
136
  .action(async (options) => {
206
137
  if (options.verbose) {
207
138
  logging_1.Logger.instance.logLevel = logging_1.LogLevel.DEBUG;
208
139
  }
140
+ const when = options.when?.toString()?.trim().toLowerCase();
141
+ if (!['auto', 'always', 'never'].includes(when)) {
142
+ logging_1.Logger.instance.error(`Invalid --when value: ${when}. Expected auto, always or never.`);
143
+ process.exit(1);
144
+ }
145
+ const token = options.token?.toString()?.trim() || undefined;
146
+ // Mask token in CI environments before any potential logging
147
+ logging_1.Logger.instance.maskCredential(token);
209
148
  logging_1.Logger.instance.debugOptions(options);
210
- const client = new license_client_1.LicensingClient();
211
149
  const licenseStr = options.license?.toString()?.trim();
212
150
  if (!licenseStr || licenseStr.length === 0) {
213
151
  logging_1.Logger.instance.error('License type is required. Use -l or --license to specify it.');
@@ -218,26 +156,19 @@ program.command('return-license')
218
156
  logging_1.Logger.instance.error(`Invalid license type: ${licenseType}`);
219
157
  process.exit(1);
220
158
  }
221
- let token = options.token;
222
- if (licenseType === license_client_1.LicenseType.floating) {
223
- if (!token || token.length === 0) {
224
- token = await (0, utilities_1.PromptForSecretInput)('Token: ');
225
- }
226
- if (!token || token.length === 0) {
227
- logging_1.Logger.instance.error('Token is required when returning a floating license. Use -t or --token to specify it.');
228
- process.exit(1);
229
- }
230
- // Mask token in CI environments before any potential logging
231
- logging_1.Logger.instance.maskCredential(token);
232
- }
233
- await client.Deactivate(licenseType, token);
159
+ await (0, license_client_1.ReturnLicense)(licenseType, token, when);
234
160
  process.exit(0);
235
161
  });
236
162
  program.command('license-context')
237
- .description('Print the current license context information.')
163
+ .description('Print the current license state from the Unity CLI and the Unity Licensing Client.')
238
164
  .action(async () => {
239
- const client = new license_client_1.LicensingClient();
240
- await client.Context();
165
+ await (0, license_client_1.PrintLicenseContext)();
166
+ process.exit(0);
167
+ });
168
+ program.command('license-file-path')
169
+ .description('Prints the path to the machine\'s Unity license file (Unity_lic.ulf).')
170
+ .action(async () => {
171
+ process.stdout.write(`${(0, license_client_1.GetLicenseFilePath)()}\n`);
241
172
  process.exit(0);
242
173
  });
243
174
  program.command('licensing-client-logs')
@@ -252,101 +183,17 @@ program.command('licensing-audit-logs')
252
183
  process.stdout.write(`${license_client_1.LicensingClient.ClientAuditLogPath()}\n`);
253
184
  process.exit(0);
254
185
  });
255
- program.commandsGroup('Unity Hub:');
256
- program.command('hub-version')
257
- .description('Print the Unity Hub version.')
258
- .action(async () => {
259
- const unityHub = new unity_hub_1.UnityHub();
260
- try {
261
- const version = await unityHub.Version();
262
- process.stdout.write(`${version}\n`);
263
- }
264
- catch (error) {
265
- process.stdout.write(`${error}\n`);
266
- }
267
- finally {
268
- process.exit(0);
269
- }
270
- });
271
- program.command('hub-path')
272
- .description('Print the path to the Unity Hub executable.')
273
- .option('--json', 'Prints the last line of output as JSON string.')
274
- .action(async (options) => {
275
- const hub = new unity_hub_1.UnityHub();
276
- logging_1.Logger.instance.CI_setEnvironmentVariable('UNITY_HUB_PATH', hub.executable);
277
- if (options.json) {
278
- process.stdout.write(`\n${JSON.stringify({ UNITY_HUB_PATH: hub.executable })}\n`);
279
- }
280
- else {
281
- process.stdout.write(`${hub.executable}\n`);
282
- }
283
- process.exit(0);
284
- });
285
- program.command('hub-logs')
286
- .description('Prints the path to the Unity Hub log file.')
287
- .action(async () => {
288
- process.stdout.write(`${unity_hub_1.UnityHub.LogPath()}\n`);
289
- process.exit(0);
290
- });
291
- program.command('package-manager-logs')
292
- .description('Prints the path to the Unity Package Manager log file.')
293
- .action(async () => {
294
- process.stdout.write(`${unity_hub_1.UnityHub.PackageManagerLogsPath()}\n`);
295
- process.exit(0);
296
- });
297
- program.command('hub-install')
298
- .description('Install or update the Unity Hub.')
299
- .option('--verbose', 'Enable verbose logging.')
300
- .option('--auto-update', 'Automatically updates the Unity Hub if it is already installed. Cannot be used with --hub-version.')
301
- .option('--hub-version <version>', 'Specify to install a specific version of Unity Hub. Cannot be used with --auto-update.')
302
- .option('--json', 'Prints the last line of output as JSON string.')
303
- .action(async (options) => {
304
- if (options.verbose) {
305
- logging_1.Logger.instance.logLevel = logging_1.LogLevel.DEBUG;
306
- }
307
- logging_1.Logger.instance.debugOptions(options);
308
- if (options.autoUpdate === true && options.hubVersion) {
309
- logging_1.Logger.instance.error('Cannot use --auto-update with --hub-version.');
310
- process.exit(1);
311
- }
312
- const unityHub = new unity_hub_1.UnityHub();
313
- const hubPath = await unityHub.Install(options.autoUpdate === true, options.hubVersion);
314
- logging_1.Logger.instance.CI_setEnvironmentVariable('UNITY_HUB_PATH', hubPath);
315
- if (options.json) {
316
- process.stdout.write(`\n${JSON.stringify({ UNITY_HUB_PATH: hubPath })}\n`);
317
- }
318
- else {
319
- process.stdout.write(`${hubPath}\n`);
320
- }
321
- process.exit(0);
322
- });
323
- program.command('hub')
324
- .description('Run commands directly to the Unity Hub. (You need not to pass --headless or -- to this command).')
325
- .option('--verbose', 'Enable verbose logging.')
326
- .option('--json', 'Prints the last line of output as a json string, which contains the operation results.')
327
- .allowUnknownOption(true)
328
- .argument('<args...>', 'Arguments to pass to the Unity Hub executable.')
329
- .action(async (args, options) => {
330
- if (options.verbose) {
331
- logging_1.Logger.instance.logLevel = logging_1.LogLevel.DEBUG;
332
- }
333
- logging_1.Logger.instance.debugOptions({ args, options });
334
- const unityHub = new unity_hub_1.UnityHub();
335
- const output = await unityHub.Exec(args, { silent: false, showCommand: logging_1.Logger.instance.logLevel === logging_1.LogLevel.DEBUG });
336
- if (options.json) {
337
- process.stdout.write(`\n${JSON.stringify({ output })}\n`);
338
- }
339
- process.exit(0);
340
- });
186
+ program.commandsGroup('Unity Editor:');
341
187
  program.command('setup-unity')
342
- .description('Find or install the Unity Editor for a project or specific version.')
188
+ .description('Find or install the Unity Editor for a project or specific version. 2017.4 and newer install with the official Unity CLI; 4.x and 5.x install from Unity\'s archives.')
343
189
  .option('-p, --unity-project <unityProject>', 'The path to a Unity project or "none" to skip project detection.')
344
190
  .option('-u, --unity-version <unityVersion>', 'The Unity version to get (e.g. 2020.3.1f1, 2021.x, 2022.1.*, 6000). If specified, it will override the version read from the project.')
345
191
  .option('-c, --changeset <changeset>', 'The Unity changeset to get (e.g. 1234567890ab).')
192
+ .option('--channel <channels>', 'Release channel letter(s) to accept when resolving partial versions: f,p,b,a,x (comma-separated). Default: f (stable only).')
346
193
  .option('-a, --arch <arch>', 'The Unity architecture to get (e.g. x86_64, arm64). Defaults to the architecture of the current process.')
347
194
  .option('-b, --build-targets <buildTargets>', 'The Unity build target to get/install as comma-separated values (e.g. iOS,Android).')
348
195
  .option('-m, --modules <modules>', 'The Unity module to get/install as comma-separated values (e.g. ios,android).')
349
- .option('-i, --install-path <installPath>', 'The path to install the Unity Editor to. By default, it will be installed to the default Unity Hub location.')
196
+ .option('-i, --install-path <installPath>', 'The path to install the Unity Editor to. By default, it will be installed to the Unity CLI install path.')
350
197
  .option('--verbose', 'Enable verbose logging.')
351
198
  .option('--json', 'Prints the last line of output as JSON string.')
352
199
  .action(async (options) => {
@@ -364,14 +211,23 @@ program.command('setup-unity')
364
211
  }
365
212
  let unityVersion;
366
213
  if (options.unityVersion) {
367
- unityVersion = new unity_version_1.UnityVersion(options.unityVersion, options.changeset, options.arch);
214
+ const arch = options.arch?.toString()?.trim().toLowerCase();
215
+ const architecture = arch === 'arm64' ? 'ARM64' : arch === 'x86_64' || arch === 'x64' ? 'X86_64' : undefined;
216
+ unityVersion = new unity_version_1.UnityVersion(options.unityVersion, options.changeset, architecture);
368
217
  }
369
218
  else {
370
219
  unityVersion = unityProject.version;
371
220
  }
372
221
  const modules = options.modules ? options.modules.split(/[ ,]+/).filter(Boolean) : [];
373
222
  const buildTargets = options.buildTargets ? options.buildTargets.split(/[ ,]+/).filter(Boolean) : [];
374
- const moduleBuildTargetMap = unity_hub_1.UnityHub.GetPlatformTargetModuleMap();
223
+ // with only a project, its saved build profiles pick the modules; --modules or --build-targets override them
224
+ if (unityProject && modules.length === 0 && buildTargets.length === 0) {
225
+ buildTargets.push(...unityProject.GetBuildProfileTargets());
226
+ if (buildTargets.length > 0) {
227
+ logging_1.Logger.instance.info(`Installing modules for the project's build profiles: ${buildTargets.join(', ')}`);
228
+ }
229
+ }
230
+ const moduleBuildTargetMap = unity_installer_1.UnityInstaller.GetPlatformTargetModuleMap();
375
231
  for (const target of buildTargets) {
376
232
  const module = moduleBuildTargetMap[target];
377
233
  if (module === undefined) {
@@ -388,11 +244,28 @@ program.command('setup-unity')
388
244
  modules.includes('None')) {
389
245
  modules.length = 0;
390
246
  }
391
- const unityHub = new unity_hub_1.UnityHub();
392
- const unityEditor = await unityHub.GetEditor(unityVersion, modules);
247
+ const channels = options.channel
248
+ ? String(options.channel).split(/[ ,]+/).map((c) => c.trim().toLowerCase()).filter(Boolean)
249
+ : ['f'];
250
+ const allowedChannels = new Set(['f', 'p', 'b', 'a', 'x']);
251
+ for (const ch of channels) {
252
+ if (!allowedChannels.has(ch)) {
253
+ logging_1.Logger.instance.error(`Invalid --channel '${ch}'. Expected one of: f, p, b, a, x.`);
254
+ process.exit(1);
255
+ }
256
+ }
257
+ const unityCli = await unity_cli_1.UnityCli.Get();
258
+ const installer = new unity_installer_1.UnityInstaller(unityCli);
259
+ if (options.installPath) {
260
+ await installer.SetInstallPath(options.installPath);
261
+ }
262
+ const unityEditor = await installer.GetEditor(unityVersion, modules, channels);
393
263
  const output = {
394
- 'UNITY_HUB_PATH': unityHub.executable,
395
- 'UNITY_EDITOR_PATH': unityEditor.editorPath
264
+ 'UNITY_CLI_PATH': unityCli.executable,
265
+ 'UNITY_EDITOR_PATH': unityEditor.editorPath,
266
+ 'UNITY_EDITOR_VERSION': unityEditor.version.version,
267
+ 'UNITY_EDITOR_CHANGESET': unityEditor.version.changeset ?? '',
268
+ 'UNITY_EDITOR_CHANNELS': channels.join(','),
396
269
  };
397
270
  if (unityProject) {
398
271
  output['UNITY_PROJECT_PATH'] = unityProject.projectPath;
@@ -418,56 +291,8 @@ program.command('setup-unity')
418
291
  }
419
292
  process.exit(0);
420
293
  });
421
- program.command('uninstall-unity')
422
- .description('Uninstall a Unity Editor version.')
423
- .option('-e, --unity-editor <unityEditor>', 'The path to the Unity Editor executable. If unspecified, -u, --unity-version or the UNITY_EDITOR_PATH environment variable must be set.')
424
- .option('-u, --unity-version <unityVersion>', 'The Unity version to get (e.g. 2020.3.1f1, 2021.x, 2022.1.*, 6000). If unspecified, then --unity-editor must be specified.')
425
- .option('-c, --changeset <changeset>', 'The Unity changeset to get (e.g. 1234567890ab).')
426
- .option('-a, --arch <arch>', 'The Unity architecture to get (e.g. x86_64, arm64). Defaults to the architecture of the current process.')
427
- .option('--verbose', 'Enable verbose logging.')
428
- .action(async (options) => {
429
- if (options.verbose) {
430
- logging_1.Logger.instance.logLevel = logging_1.LogLevel.DEBUG;
431
- }
432
- logging_1.Logger.instance.debugOptions(options);
433
- let unityEditor;
434
- const unityVersionStr = options.unityVersion?.toString()?.trim();
435
- if (unityVersionStr) {
436
- const unityVersion = new unity_version_1.UnityVersion(unityVersionStr, options.changeset, options.arch);
437
- const unityHub = new unity_hub_1.UnityHub();
438
- const installedEditors = await unityHub.ListInstalledEditors();
439
- if (unityVersion.isLegacy()) {
440
- const installPath = await unityHub.GetInstallPath();
441
- unityEditor = new unity_editor_1.UnityEditor(path.join(installPath, `Unity ${unityVersion.toString()}`, 'Unity.exe'));
442
- }
443
- else {
444
- unityEditor = installedEditors.find(e => e.version.equals(unityVersion));
445
- }
446
- }
447
- else {
448
- const editorPath = options.unityEditor?.toString()?.trim() || process.env.UNITY_EDITOR_PATH || undefined;
449
- if (!editorPath || editorPath.length === 0) {
450
- logging_1.Logger.instance.error('You must specify a Unity version or editor path with -u, --unity-version, -e, --unity-editor.');
451
- process.exit(1);
452
- }
453
- try {
454
- unityEditor = new unity_editor_1.UnityEditor(editorPath);
455
- }
456
- catch {
457
- // ignored
458
- }
459
- }
460
- if (!unityEditor) {
461
- logging_1.Logger.instance.info('The specified Unity Editor was not found.');
462
- }
463
- else {
464
- await unityEditor.Uninstall();
465
- }
466
- process.exit(0);
467
- });
468
- program.commandsGroup('Unity Editor:');
469
294
  program.command('run')
470
- .description('Run Unity Editor command line arguments (passes args directly to the editor).')
295
+ .description('Run Unity Editor command line arguments with live Editor log and UTP annotations. Runs with a project go through the official CLI\'s unity run.')
471
296
  .option('--unity-editor <unityEditor>', 'The path to the Unity Editor executable. If unspecified, --unity-project or the UNITY_EDITOR_PATH environment variable must be set.')
472
297
  .option('--unity-project <unityProject>', 'The path to a Unity project. If unspecified, the UNITY_PROJECT_PATH environment variable will be used, otherwise no project will be specified.')
473
298
  .option('--log-name <logName>', 'The name of the log file.')
@@ -545,9 +370,8 @@ program.command('run')
545
370
  process.exit(1);
546
371
  }
547
372
  if (!unityEditor) {
548
- const unityHub = new unity_hub_1.UnityHub();
549
373
  try {
550
- unityEditor = await unityHub.GetEditor(unityProject.version);
374
+ unityEditor = await new unity_installer_1.UnityInstaller().GetEditor(unityProject.version);
551
375
  }
552
376
  catch {
553
377
  logging_1.Logger.instance.error(`Could not find Unity Editor version ${unityProject.version.version} installed for project at ${unityProject.projectPath}. Please specify the editor path with --unity-editor or set the UNITY_EDITOR_PATH environment variable.`);
@@ -569,127 +393,99 @@ program.command('run')
569
393
  });
570
394
  process.exit(0);
571
395
  });
572
- program.command('list-project-templates')
573
- .description('List available Unity project templates for an editor.')
574
- .option('-u, --unity-version <unityVersion>', 'The Unity version to get (e.g. 2020.3.1f1, 2021.x, 2022.1.*, 6000). If unspecified, then --unity-editor must be specified.')
396
+ program.command('editor-logs')
397
+ .description('Prints the path to the Unity Editor log files.')
398
+ .action(async () => {
399
+ const unityEditorLogsPath = unity_editor_1.UnityEditor.GetEditorLogsDirectory();
400
+ process.stdout.write(`${unityEditorLogsPath}\n`);
401
+ process.exit(0);
402
+ });
403
+ program.commandsGroup('Deprecated, forwarded to the official Unity CLI:');
404
+ program.command('uninstall-unity')
405
+ .description('[Deprecated] Uninstall a Unity Editor version. Forwards to: unity uninstall <version> --yes')
575
406
  .option('-e, --unity-editor <unityEditor>', 'The path to the Unity Editor executable. If unspecified, -u, --unity-version or the UNITY_EDITOR_PATH environment variable must be set.')
407
+ .option('-u, --unity-version <unityVersion>', 'The Unity version to uninstall (e.g. 2020.3.1f1, 6000.2). If unspecified, then --unity-editor must be specified.')
408
+ .option('-c, --changeset <changeset>', 'Ignored; the official CLI uninstalls by version.')
409
+ .option('-a, --arch <arch>', 'The Unity architecture to uninstall (x86_64, arm64).')
576
410
  .option('--verbose', 'Enable verbose logging.')
577
- .option('--json', 'Prints the last line of output as JSON string.')
578
411
  .action(async (options) => {
579
412
  if (options.verbose) {
580
413
  logging_1.Logger.instance.logLevel = logging_1.LogLevel.DEBUG;
581
414
  }
582
415
  logging_1.Logger.instance.debugOptions(options);
583
- const unityVersionStr = options.unityVersion?.toString()?.trim();
584
- const editorFromEnv = process.env.UNITY_EDITOR_PATH?.trim();
585
- if (!unityVersionStr && !options.unityEditor?.toString()?.trim() && !editorFromEnv) {
586
- logging_1.Logger.instance.error('You must specify a Unity version or editor path with -u, --unity-version, -e, --unity-editor, or set UNITY_EDITOR_PATH.');
416
+ const version = await forwardedEditorVersion(options);
417
+ if (!version) {
418
+ logging_1.Logger.instance.error('You must specify the Unity version or editor path with -u, --unity-version, -e, --unity-editor or UNITY_EDITOR_PATH.');
587
419
  process.exit(1);
588
420
  }
589
- let unityEditor;
590
- if (unityVersionStr) {
591
- const unityVersion = new unity_version_1.UnityVersion(unityVersionStr);
592
- unityEditor = await new unity_hub_1.UnityHub().GetEditor(unityVersion);
593
- }
594
- else {
595
- const editorPath = options.unityEditor?.toString()?.trim() || editorFromEnv;
596
- if (!editorPath || editorPath.length === 0) {
597
- throw new Error('The Unity Editor path was not specified. Use -e or --unity-editor to specify it, or set the UNITY_EDITOR_PATH environment variable.');
598
- }
599
- unityEditor = new unity_editor_1.UnityEditor(editorPath);
421
+ const args = ['uninstall', version, '--yes'];
422
+ const arch = options.arch?.toString()?.trim();
423
+ if (arch) {
424
+ args.push('--architecture', arch);
600
425
  }
601
- const templates = unityEditor.GetAvailableTemplates();
602
- if (templates.length > 0) {
603
- if (options.json) {
604
- process.stdout.write(`\n${JSON.stringify({ templates })}\n`);
605
- }
606
- else {
607
- process.stdout.write(`Available project templates:\n${templates.map(t => ` - ${path.basename(t)}`).join('\n')}\n`);
608
- }
609
- }
610
- else {
611
- process.stdout.write('No project templates found for this Unity Editor.\n');
426
+ await forwardToUnityCli('uninstall-unity', args);
427
+ });
428
+ program.command('list-project-templates')
429
+ .description('[Deprecated] List available Unity project templates for an editor. Forwards to: unity templates list --editor <version>')
430
+ .option('-u, --unity-version <unityVersion>', 'The Unity version to list templates for (e.g. 2022.3.1f1, 6000.2). If unspecified, then --unity-editor must be specified.')
431
+ .option('-e, --unity-editor <unityEditor>', 'The path to the Unity Editor executable. If unspecified, -u, --unity-version or the UNITY_EDITOR_PATH environment variable must be set.')
432
+ .option('--verbose', 'Enable verbose logging.')
433
+ .option('--json', 'Prints the output as JSON.')
434
+ .action(async (options) => {
435
+ if (options.verbose) {
436
+ logging_1.Logger.instance.logLevel = logging_1.LogLevel.DEBUG;
612
437
  }
613
- process.exit(0);
438
+ logging_1.Logger.instance.debugOptions(options);
439
+ const version = await forwardedEditorVersion(options, true);
440
+ await forwardToUnityCli('list-project-templates', ['templates', 'list', ...(version ? ['--editor', version] : [])], options.json === true);
614
441
  });
615
442
  program.command('create-project')
616
- .description('Create a new Unity project.')
443
+ .description('[Deprecated] Create a new Unity project. Forwards to: unity projects create <name> --path <path> --editor-version <version> --template <id> --no-cloud')
617
444
  .option('-n, --name <projectName>', 'The name of the new Unity project. If unspecified, the project will be created in the specified path or the current working directory.')
618
445
  .option('-p, --path <projectPath>', 'The path to create the new Unity project. If unspecified, the current working directory will be used.')
619
- .option('-t, --template <projectTemplate>', 'The name of the template package to use for creating the unity project. Supports regex patterns.', 'com.unity.template.3d(-cross-platform)?')
620
- .option('-u, --unity-version <unityVersion>', 'The Unity version to get (e.g. 2020.3.1f1, 2021.x, 2022.1.*, 6000). If unspecified, then --unity-editor must be specified.')
446
+ .option('-t, --template <projectTemplate>', 'The template package id to create the project from; an id prefix picks the first matching template.', 'com.unity.template.3d')
447
+ .option('-u, --unity-version <unityVersion>', 'The Unity version to create the project with (e.g. 2022.3.1f1, 6000.2). If unspecified, then --unity-editor must be specified.')
621
448
  .option('-e, --unity-editor <unityEditor>', 'The path to the Unity Editor executable. If unspecified, -u, --unity-version, or the UNITY_EDITOR_PATH environment variable must be set.')
622
449
  .option('--verbose', 'Enable verbose logging.')
623
- .option('--json', 'Prints the last line of output as JSON string.')
450
+ .option('--json', 'Prints the output as JSON.')
624
451
  .action(async (options) => {
625
452
  if (options.verbose) {
626
453
  logging_1.Logger.instance.logLevel = logging_1.LogLevel.DEBUG;
627
454
  }
628
455
  logging_1.Logger.instance.debugOptions(options);
629
- const unityVersionStr = options.unityVersion?.toString()?.trim();
630
- const editorFromEnv = process.env.UNITY_EDITOR_PATH?.trim();
631
- if (!unityVersionStr && !options.unityEditor?.toString()?.trim() && !editorFromEnv) {
632
- logging_1.Logger.instance.error('You must specify a Unity version or editor path with -u, --unity-version, -e, --unity-editor, or set UNITY_EDITOR_PATH.');
456
+ const version = await forwardedEditorVersion(options, true);
457
+ const target = path.resolve(options.path?.toString()?.trim() || process.cwd());
458
+ const name = options.name?.toString()?.trim();
459
+ const args = ['projects', 'create', name || path.basename(target), '--path', name ? target : path.dirname(target)];
460
+ if (version) {
461
+ args.push('--editor-version', version);
462
+ }
463
+ const template = options.template.toString().trim();
464
+ // v3 took a regex here; a pattern is never compiled from the argument, so its leading literal part
465
+ // (com.unity.template.3d for the v3 default) is matched as an exact id, then as an id prefix
466
+ const prefix = /^[\w.-]+/.exec(template)?.[0];
467
+ if (!prefix) {
468
+ logging_1.Logger.instance.error(`Invalid project template: ${template}. Use a template id such as com.unity.template.3d.`);
633
469
  process.exit(1);
634
470
  }
635
- let unityEditor;
636
- if (unityVersionStr) {
637
- const unityVersion = new unity_version_1.UnityVersion(unityVersionStr);
638
- unityEditor = await new unity_hub_1.UnityHub().GetEditor(unityVersion);
639
- }
640
- else {
641
- const editorPath = options.unityEditor?.toString()?.trim() || editorFromEnv;
642
- if (!editorPath || editorPath.length === 0) {
643
- logging_1.Logger.instance.error('The Unity Editor path was not specified. Use -e or --unity-editor to specify it, or set the UNITY_EDITOR_PATH environment variable.');
644
- process.exit(1);
645
- }
646
- unityEditor = new unity_editor_1.UnityEditor(editorPath);
647
- }
648
- let args = [
649
- '-quit',
650
- '-nographics',
651
- '-batchmode'
652
- ];
653
- const projectName = options.name?.toString()?.trim();
654
- let projectPath = options.path?.toString()?.trim() || process.cwd();
655
- if (projectName && projectName.length > 0) {
656
- projectPath = path.join(projectPath, projectName);
657
- }
658
- args.push('-createProject', projectPath);
659
- if (options.template && options.template.length > 0) {
660
- const availableTemplates = unityEditor.GetAvailableTemplates();
661
- if (availableTemplates.length === 0) {
662
- if (unityEditor.version.isLessThan('2019.0.0')) {
663
- logging_1.Logger.instance.info(`Skipping template selection for Unity ${unityEditor.version.toString()} because project templates are not supported.`);
664
- }
665
- else {
666
- throw new Error(`No Unity project templates found for ${unityEditor.version.toString()}`);
667
- }
668
- }
669
- else {
670
- const templatePath = unityEditor.GetTemplatePath(options.template) ??
671
- unityEditor.GetTemplatePath('com\\.unity\\.template\\.urp-[\\w-]+') ??
672
- availableTemplates[0];
673
- if (!templatePath) {
674
- throw new Error(`No Unity project template found for ${options.template}`);
675
- }
676
- args.push('-cloneFromTemplate', templatePath);
677
- }
678
- }
679
- await unityEditor.Run({ projectPath, args });
680
- logging_1.Logger.instance.CI_setEnvironmentVariable('UNITY_PROJECT_PATH', projectPath);
681
- if (options.json) {
682
- process.stdout.write(`\n${JSON.stringify({ UNITY_PROJECT_PATH: projectPath })}\n`);
471
+ if (prefix !== template) {
472
+ logging_1.Logger.instance.warn(`Template patterns are no longer supported; matching templates that start with ${prefix}.`);
683
473
  }
684
- else {
685
- process.stdout.write(`Unity project created at: ${projectPath}\n`);
474
+ const cli = await unity_cli_1.UnityCli.Get();
475
+ const { envelope } = await cli.RunJson(['templates', 'list', ...(version ? ['--editor', version] : [])]);
476
+ const ids = (envelope?.data ?? []).map(t => t.name || t.id).filter((id) => !!id);
477
+ const templateId = ids.find(id => id === prefix) ?? ids.find(id => id.startsWith(prefix));
478
+ if (!templateId) {
479
+ logging_1.Logger.instance.error(`No project template matches ${prefix}. Available: ${ids.join(', ')}`);
480
+ process.exit(1);
686
481
  }
687
- process.exit(0);
482
+ args.push('--template', templateId, '--no-cloud');
483
+ await forwardToUnityCli('create-project', args, options.json === true);
688
484
  });
689
485
  program.command('open-project')
690
- .description('Open a Unity project in the Unity Editor.')
486
+ .description('[Deprecated] Open a Unity project in the Unity Editor. Forwards to: unity open <project>')
691
487
  .option('-p, --unity-project <unityProject>', 'The path to a Unity project. If unspecified, the UNITY_PROJECT_PATH environment variable or the current working directory will be used.')
692
- .option('-u, --unity-version <unityVersion>', 'The Unity version to get (e.g. 2020.3.1f1, 2021.x, 2022.1.*, 6000). If specified, it will override the version read from the project.')
488
+ .option('-u, --unity-version <unityVersion>', 'The Unity version to open the project with. If specified, it will override the version read from the project.')
693
489
  .option('-t, --build-target <buildTarget>', 'The Unity build target to switch the project to (e.g. StandaloneWindows64, StandaloneOSX, iOS, Android).')
694
490
  .option('--verbose', 'Enable verbose logging.')
695
491
  .action(async (options) => {
@@ -697,47 +493,48 @@ program.command('open-project')
697
493
  logging_1.Logger.instance.logLevel = logging_1.LogLevel.DEBUG;
698
494
  }
699
495
  logging_1.Logger.instance.debugOptions(options);
700
- const projectPath = options.unityProject?.toString()?.trim() ||
701
- process.env.UNITY_PROJECT_PATH ||
702
- undefined;
703
- const unityProject = await unity_project_1.UnityProject.GetProject(projectPath);
704
- if (!unityProject) {
705
- logging_1.Logger.instance.error(`The specified path is not a valid Unity project: ${projectPath}`);
706
- process.exit(1);
707
- }
708
- let unityVersion = unityProject?.version;
709
- if (options.unityVersion) {
710
- unityVersion = new unity_version_1.UnityVersion(options.unityVersion);
711
- }
496
+ const projectPath = options.unityProject?.toString()?.trim() || process.env.UNITY_PROJECT_PATH || process.cwd();
497
+ const args = ['open', projectPath];
498
+ const version = options.unityVersion?.toString()?.trim();
712
499
  const buildTarget = options.buildTarget?.toString()?.trim();
713
- let module = undefined;
714
- if (buildTarget && buildTarget.length > 0) {
715
- const moduleBuildTargetMap = unity_hub_1.UnityHub.GetPlatformTargetModuleMap();
716
- module = moduleBuildTargetMap[buildTarget] ? [moduleBuildTargetMap[buildTarget]] : undefined;
717
- }
718
- const unityHub = new unity_hub_1.UnityHub();
719
- const unityEditor = await unityHub.GetEditor(unityVersion, module);
720
- logging_1.Logger.instance.info(`Opening "${unityProject.projectPath}" with Unity ${unityEditor.version}${buildTarget ? ` - ${buildTarget}` : ''}...`);
721
- const openArgs = ['-projectPath', unityProject.projectPath];
722
- if (buildTarget && buildTarget.length > 0) {
723
- openArgs.push('-buildTarget', buildTarget);
724
- }
725
- let child = null;
726
- try {
727
- child = (0, child_process_1.spawn)(unityEditor.editorPath, openArgs, { detached: true });
728
- child.unref();
500
+ if (version) {
501
+ args.push('--editor-version', version);
729
502
  }
730
- finally {
731
- process.exit(child?.pid !== undefined ? 0 : 1);
503
+ if (buildTarget) {
504
+ args.push('--build-target', buildTarget);
732
505
  }
506
+ await forwardToUnityCli('open-project', args);
733
507
  });
734
- program.command('editor-logs')
735
- .description('Prints the path to the Unity Editor log files.')
736
- .action(async () => {
737
- const unityEditorLogsPath = unity_editor_1.UnityEditor.GetEditorLogsDirectory();
738
- process.stdout.write(`${unityEditorLogsPath}\n`);
739
- process.exit(0);
740
- });
508
+ /**
509
+ * The editor version a forwarded v3 command names, from --unity-version or the editor at --unity-editor / UNITY_EDITOR_PATH.
510
+ * Partial versions such as 2021.3.x become 2021.3, the short form `unity uninstall` accepts; with `exact`, they resolve
511
+ * to the newest matching release instead, because `unity templates list` and `unity projects create` need a full version.
512
+ */
513
+ async function forwardedEditorVersion(options, exact = false) {
514
+ const version = options.unityVersion?.toString()?.trim();
515
+ if (version) {
516
+ if (!exact) {
517
+ return version.replace(/\.[x*]$/i, '');
518
+ }
519
+ const unityVersion = new unity_version_1.UnityVersion(version);
520
+ if (unityVersion.isFullyQualified()) {
521
+ return unityVersion.version;
522
+ }
523
+ return (await new unity_installer_1.UnityInstaller(await unity_cli_1.UnityCli.Get()).resolveVersion(unityVersion)).version;
524
+ }
525
+ const editorPath = options.unityEditor?.toString()?.trim() || process.env.UNITY_EDITOR_PATH;
526
+ return editorPath ? new unity_editor_1.UnityEditor(editorPath).version.version : undefined;
527
+ }
528
+ /** Warns that a v3 command is deprecated, runs its official Unity CLI replacement and exits with that exit code. */
529
+ async function forwardToUnityCli(command, args, json = false) {
530
+ logging_1.Logger.instance.warn(`unity-cli ${command} is deprecated and will be removed. Use the official Unity CLI instead: unity ${args.join(' ')}`);
531
+ const cli = await unity_cli_1.UnityCli.Get();
532
+ const result = await cli.Run(json ? [...args, '--json'] : args, { stream: !json });
533
+ if (json) {
534
+ process.stdout.write(`${result.stdout.trim()}\n`);
535
+ }
536
+ process.exit(result.exitCode);
537
+ }
741
538
  program.commandsGroup("Unity Package Manager:");
742
539
  program.command('upm-install')
743
540
  .description('Download and install the Unity Package Manager cli (pack/sign).')
@@ -791,7 +588,7 @@ program.command('upm-install')
791
588
  process.exit(0);
792
589
  }
793
590
  catch (error) {
794
- logging_1.Logger.instance.error(`${error}`);
591
+ (0, failure_markers_1.ReportFailure)(error);
795
592
  process.exit(1);
796
593
  }
797
594
  });
@@ -805,7 +602,7 @@ program.command('upm-version')
805
602
  process.exit(0);
806
603
  }
807
604
  catch (error) {
808
- logging_1.Logger.instance.error(`${error}`);
605
+ (0, failure_markers_1.ReportFailure)(error);
809
606
  process.exit(1);
810
607
  }
811
608
  });
@@ -870,120 +667,12 @@ program.command('upm-pack')
870
667
  process.exit(0);
871
668
  }
872
669
  catch (error) {
873
- logging_1.Logger.instance.error(`${error}`);
874
- process.exit(1);
875
- }
876
- });
877
- program.command('sign-package')
878
- .description('[Deprecated] Sign a Unity package using Unity Editor 6000.3+ batch mode (-upmPack). Use unity-cli upm-pack with organization and service account credentials for new workflows.')
879
- .option('--package <package>', 'Required. The fully qualified path to the folder that contains the package.json file for the package you want to sign. Note: Don\'t include package.json in this parameter value.')
880
- .option('--output <output>', 'Optional. The output directory where you want to save the signed tarball file (.tgz). If unspecified, the package contents will be updated in place with the signed .attestation.p7m file.')
881
- .option('--email <email>', 'Email associated with the Unity account. If unspecified, the UNITY_USERNAME environment variable will be used.')
882
- .option('--password <password>', 'The password of the Unity account. If unspecified, the UNITY_PASSWORD environment variable will be used.')
883
- .option('--organization <organization>', 'The Organization ID you copied from the Unity Cloud Dashboard. If unspecified, the UNITY_ORGANIZATION_ID environment variable will be used.')
884
- .option('--verbose', 'Enable verbose logging.')
885
- .action(async (options) => {
886
- logging_1.Logger.instance.warn('The sign-package command is deprecated. Use unity-cli upm-pack --source <path-to-package-folder> --destination <output-path> with UNITY_ORGANIZATION_ID or UNITY_ORG_ID, UPM_SERVICE_ACCOUNT_KEY_ID, and UPM_SERVICE_ACCOUNT_KEY_SECRET (or secure prompts).');
887
- if (options.verbose) {
888
- logging_1.Logger.instance.logLevel = logging_1.LogLevel.DEBUG;
889
- }
890
- logging_1.Logger.instance.debugOptions(options);
891
- const packagePath = path.normalize(options.package?.toString()?.trim());
892
- if (!packagePath || packagePath.length === 0) {
893
- logging_1.Logger.instance.error('The package path is required. Use --package to specify it.');
894
- process.exit(1);
895
- }
896
- const packageJsonPath = path.join(packagePath, 'package.json');
897
- try {
898
- await fs.promises.access(packageJsonPath, fs.constants.R_OK);
899
- }
900
- catch {
901
- logging_1.Logger.instance.error(`Failed to find a valid package.json file at: ${packageJsonPath}`);
902
- process.exit(1);
903
- }
904
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
905
- let outputPath = options.output?.toString()?.trim();
906
- if (outputPath && outputPath.length > 0) {
907
- outputPath = path.resolve(outputPath);
908
- if (outputPath.endsWith('.tgz')) {
909
- // remove .tgz if present
910
- outputPath = outputPath.substring(0, outputPath.length - 4);
911
- }
912
- }
913
- else {
914
- outputPath = path.join(path.resolve(packagePath, '..'));
915
- }
916
- let username = options.email?.toString()?.trim() || process.env.UNITY_USERNAME || undefined;
917
- if (!username || username.length === 0) {
918
- username = await (0, utilities_1.PromptForSecretInput)('Email: ');
919
- }
920
- if (!username || username.length === 0) {
921
- logging_1.Logger.instance.error('The email is required. Use --email to specify it.');
922
- process.exit(1);
923
- }
924
- let password = options.password?.toString()?.trim() || process.env.UNITY_PASSWORD || undefined;
925
- if (!password || password.length === 0) {
926
- password = await (0, utilities_1.PromptForSecretInput)('Password: ');
927
- }
928
- if (!password || password.length === 0) {
929
- logging_1.Logger.instance.error('The password is required. Use --password to specify it.');
930
- process.exit(1);
931
- }
932
- let organization = options.organization?.toString()?.trim() || process.env.UNITY_ORGANIZATION_ID || undefined;
933
- if (!organization || organization.length === 0) {
934
- organization = await (0, utilities_1.PromptForSecretInput)('Organization ID: ');
935
- }
936
- if (!organization || organization.length === 0) {
937
- logging_1.Logger.instance.error('The organization ID is required. Use --organization to specify it.');
670
+ (0, failure_markers_1.ReportFailure)(error);
938
671
  process.exit(1);
939
672
  }
940
- // Mask credentials in CI environments before any potential logging
941
- logging_1.Logger.instance.maskCredential(username);
942
- logging_1.Logger.instance.maskCredential(password);
943
- logging_1.Logger.instance.maskCredential(organization);
944
- // must use a unity editor 6000.3 or newer
945
- const unityVersion = new unity_version_1.UnityVersion('6000.3');
946
- const unityHub = new unity_hub_1.UnityHub();
947
- const unityEditor = await unityHub.GetEditor(unityVersion, undefined, ['f', 'b']);
948
- try {
949
- await unityEditor.Run({
950
- args: [
951
- '-batchmode',
952
- '-username', username,
953
- '-password', password,
954
- '-upmPack', packagePath, path.normalize(outputPath),
955
- '-cloudOrganization', organization
956
- ]
957
- });
958
- }
959
- catch (error) {
960
- // currently the editor returns exit code 1 even on success
961
- }
962
- finally {
963
- if (fs.existsSync(outputPath)) {
964
- const pkg = await (0, utilities_1.ResolveGlobToPath)([outputPath, `${path.basename(packageJson.name)}*.tgz`]);
965
- logging_1.Logger.instance.info(`Package signed successfully: ${pkg}`);
966
- // if the output directory was not specified in the command options,
967
- // then unpack the .tgz file and overwrite the package contents.
968
- if (!options.output || options.output.length === 0) {
969
- await tar.x({
970
- file: pkg,
971
- cwd: packagePath,
972
- strip: 1
973
- });
974
- logging_1.Logger.instance.info(`Package contents extracted to: ${packagePath}`);
975
- fs.unlinkSync(pkg);
976
- }
977
- process.exit(0);
978
- }
979
- else {
980
- logging_1.Logger.instance.error('Failed to sign the package.');
981
- process.exit(1);
982
- }
983
- }
984
673
  });
985
674
  void program.parseAsync(process.argv).catch((err) => {
986
- logging_1.Logger.instance.error(err instanceof Error ? err.message : String(err));
675
+ (0, failure_markers_1.ReportFailure)(err);
987
676
  process.exit(1);
988
677
  });
989
678
  //# sourceMappingURL=cli.js.map