diff --git a/CHANGELOG.md b/CHANGELOG.md index 75ab4b8..6cb2079 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.10] + +### Changed + +- Updated dependencies +- Keep process running if log streaming fails + ## [1.0.9] ### Added diff --git a/lib/unity-log-streamer.ts b/lib/unity-log-streamer.ts index 1448fd7..aec8d68 100644 --- a/lib/unity-log-streamer.ts +++ b/lib/unity-log-streamer.ts @@ -8,86 +8,62 @@ import tail from 'tail'; */ export class UnityLogStreamer { - /** - * Prints the Unity log open headers to the console. - */ - public static printOpen(): void { + private static logTail: tail.Tail | null | undefined; + + private static printOpen(): void { console.log("================================ UNITY LOG ===================================") } + private static printClose(): void { + console.log("=============================== UNITY LOG END ================================"); + } + /** - * Streams the contents of a given logfile to the console and finished the Unity process. + * Streams the contents of a given Unity logfile to the console. * @param logFilePath The path to the log file that should be streamed to console. - * @param execResult The result retrieved from kicking of the Unity process. */ - public static async stream(logFilePath: string, execResult: Q.Promise): Promise { - const logTail = new tail.Tail(logFilePath, { - fromBeginning: true, - follow: true, - logger: console, - useWatchFile: true, - flushAtEOF: true, - fsWatchOptions: { - interval: 1009 - } - }); - - let exitCode = -1; - - logTail.on("error", (error) => { - console.error('ERROR: ', error); - }); - - logTail.on("line", (data) => { - console.log(data); - if (data.includes('Crash!!!')) { - exitCode = -1; - } - }); - + public static startStreaming(logFilePath: string): void { try { - exitCode = await execResult; - logTail.unwatch(); - return exitCode; - } catch (e) { - if (logTail) { - logTail.unwatch(); - } + UnityLogStreamer.printOpen(); - if (e instanceof Error) { - // WORKAROUND for license activation - // The unity exe might return the error code 3221225477 and throw an - // error because it can't write the license file on the agent, due to - // missing access rights. Nontheless the Unity process has finished - // its operation at this point and we can ignore this specific error, - // since the license is going to get released anyways after the pipeline - // has finished. - if (e.message.includes('exit code 3221225477')) { - exitCode = 0; + UnityLogStreamer.logTail = new tail.Tail(logFilePath, { + fromBeginning: true, + follow: true, + logger: console, + useWatchFile: true, + flushAtEOF: true, + fsWatchOptions: { + interval: 1009 } + }); - // WORKAROUND for Unity testing - // Exit code 2 means the Unity process did run successfully but at least one - // test has failed. In this case we want to handle the exit code as a non-error code. - if (e.message.includes('exit code 2')) { - exitCode = 2; - } - } + UnityLogStreamer.logTail.on("error", (error) => { + console.error('ERROR: ', error); + }); + + UnityLogStreamer.logTail.on("line", (data) => { + console.log(data); + }); + } catch (e) { + UnityLogStreamer.stopStreaming(); if (e instanceof Error) { console.error(e.message); } else { console.error(e); } - - return exitCode; } } /** - * Prints the Unity log close header to the console. + * Stops streaming the contents of a Unity logfile to the console. */ - public static printClose(): void { - console.log("=============================== UNITY LOG END ================================"); + public static stopStreaming(): void { + if (UnityLogStreamer.logTail) { + UnityLogStreamer.logTail.unwatch(); + UnityLogStreamer.printClose(); + } + + UnityLogStreamer.logTail = null; } } diff --git a/lib/unity-tool-runner.ts b/lib/unity-tool-runner.ts index 8ecaa38..1df4c09 100644 --- a/lib/unity-tool-runner.ts +++ b/lib/unity-tool-runner.ts @@ -20,15 +20,48 @@ export class UnityToolRunner { * @returns Unity exit code. */ public static async run(tool: ToolRunner, logFilePath: string): Promise { - const execResult = tool.exec(); - while (execResult.isPending() && !fs.existsSync(logFilePath)) { + let resultPending = true; + let execResult = -1; + + // Run the Unity command line. + tool.execAsync().then((value) => { + execResult = value; + resultPending = false; + }).catch((error) => { + console.error(error); + resultPending = false; + }); + + try { + // Wait for the log file to be created. + let waitedLoops = 0; + const maxLoops = 5; + while (!fs.existsSync(logFilePath) && waitedLoops < maxLoops) { + await Utilities.sleep(1000); + waitedLoops++; + } + + // If for some reason the log file was not created, then we skip + // streaming the log to console but still let the Unity process run. + if (waitedLoops < maxLoops) { + // Now we can start streaming it. + UnityLogStreamer.startStreaming(logFilePath); + } + } catch (e) { + if (e instanceof Error) { + console.error(e.message); + } else { + console.error(e); + } + } + + while (resultPending) { await Utilities.sleep(1000); } - UnityLogStreamer.printOpen(); - const result = await UnityLogStreamer.stream(logFilePath, execResult); - UnityLogStreamer.printClose(); + // Clean up and finish. + UnityLogStreamer.stopStreaming(); - return result; + return execResult; } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 5b0d9ff..98be03f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,22 +1,22 @@ { "name": "@dinomite-studios/unity-azure-pipelines-tasks-lib", - "version": "1.0.5", + "version": "1.0.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@dinomite-studios/unity-azure-pipelines-tasks-lib", - "version": "1.0.5", + "version": "1.0.10", "license": "MIT", "dependencies": { - "azure-pipelines-task-lib": "^4.17.2", + "azure-pipelines-task-lib": "^4.17.3", "sanitize-filename": "^1.6.3", "tail": "^2.2.6" }, "devDependencies": { "@types/chai": "^4.3.0", "@types/mocha": "^10.0.8", - "@types/node": "^22.5.5", + "@types/node": "^22.10.1", "@types/q": "^1.5.8", "@types/tail": "^2.2.3", "chai": "^4.5.0", @@ -99,12 +99,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "22.5.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", - "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", + "version": "22.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", "dev": true, "dependencies": { - "undici-types": "~6.19.2" + "undici-types": "~6.20.0" } }, "node_modules/@types/q": { @@ -227,9 +227,9 @@ } }, "node_modules/azure-pipelines-task-lib": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-4.17.2.tgz", - "integrity": "sha512-kKG1I2cpHM0kqn/YlnZiA2J59/x4OraEZZ1/Cp6A7XOu0e+E1PfrfldVVOU/tdeW/xOFoexqA4EEV27LfH0YqQ==", + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-4.17.3.tgz", + "integrity": "sha512-UxfH5pk3uOHTi9TtLtdDyugQVkFES5A836ZEePjcs3jYyxm3EJ6IlFYq6gbfd6mNBhrM9fxG2u/MFYIJ+Z0cxQ==", "dependencies": { "adm-zip": "^0.5.10", "minimatch": "3.0.5", @@ -1347,9 +1347,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true }, "node_modules/utf8-byte-length": { diff --git a/package.json b/package.json index a99f524..e6e1ea1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dinomite-studios/unity-azure-pipelines-tasks-lib", - "version": "1.0.9", + "version": "1.0.10", "description": "A library containing common implementations for pipeline tasks available in the Unity Tools for Azure DevOps extension.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -26,14 +26,14 @@ "author": "Dinomite", "license": "MIT", "dependencies": { - "azure-pipelines-task-lib": "^4.17.2", + "azure-pipelines-task-lib": "^4.17.3", "sanitize-filename": "^1.6.3", "tail": "^2.2.6" }, "devDependencies": { "@types/chai": "^4.3.0", "@types/mocha": "^10.0.8", - "@types/node": "^22.5.5", + "@types/node": "^22.10.1", "@types/tail": "^2.2.3", "@types/q": "^1.5.8", "chai": "^4.5.0", diff --git a/test/Packages/manifest.json b/test/Packages/manifest.json index 389bcf8..a1d5024 100644 --- a/test/Packages/manifest.json +++ b/test/Packages/manifest.json @@ -1,47 +1 @@ -{ - "dependencies": { - "com.unity.ai.navigation": "2.0.4", - "com.unity.collab-proxy": "2.5.1", - "com.unity.ide.rider": "3.0.31", - "com.unity.ide.visualstudio": "2.0.22", - "com.unity.inputsystem": "1.11.0", - "com.unity.multiplayer.center": "1.0.0", - "com.unity.render-pipelines.universal": "17.0.3", - "com.unity.test-framework": "1.4.5", - "com.unity.timeline": "1.8.7", - "com.unity.ugui": "2.0.0", - "com.unity.visualscripting": "1.9.4", - "com.unity.modules.accessibility": "1.0.0", - "com.unity.modules.ai": "1.0.0", - "com.unity.modules.androidjni": "1.0.0", - "com.unity.modules.animation": "1.0.0", - "com.unity.modules.assetbundle": "1.0.0", - "com.unity.modules.audio": "1.0.0", - "com.unity.modules.cloth": "1.0.0", - "com.unity.modules.director": "1.0.0", - "com.unity.modules.imageconversion": "1.0.0", - "com.unity.modules.imgui": "1.0.0", - "com.unity.modules.jsonserialize": "1.0.0", - "com.unity.modules.particlesystem": "1.0.0", - "com.unity.modules.physics": "1.0.0", - "com.unity.modules.physics2d": "1.0.0", - "com.unity.modules.screencapture": "1.0.0", - "com.unity.modules.terrain": "1.0.0", - "com.unity.modules.terrainphysics": "1.0.0", - "com.unity.modules.tilemap": "1.0.0", - "com.unity.modules.ui": "1.0.0", - "com.unity.modules.uielements": "1.0.0", - "com.unity.modules.umbra": "1.0.0", - "com.unity.modules.unityanalytics": "1.0.0", - "com.unity.modules.unitywebrequest": "1.0.0", - "com.unity.modules.unitywebrequestassetbundle": "1.0.0", - "com.unity.modules.unitywebrequestaudio": "1.0.0", - "com.unity.modules.unitywebrequesttexture": "1.0.0", - "com.unity.modules.unitywebrequestwww": "1.0.0", - "com.unity.modules.vehicles": "1.0.0", - "com.unity.modules.video": "1.0.0", - "com.unity.modules.vr": "1.0.0", - "com.unity.modules.wind": "1.0.0", - "com.unity.modules.xr": "1.0.0" - } -} \ No newline at end of file +{"dependencies":{"com.unity.ai.navigation":"2.0.4","com.unity.collab-proxy":"2.5.1","com.unity.ide.rider":"3.0.31","com.unity.ide.visualstudio":"2.0.22","com.unity.inputsystem":"1.11.0","com.unity.multiplayer.center":"1.0.0","com.unity.render-pipelines.universal":"17.0.3","com.unity.test-framework":"1.4.5","com.unity.timeline":"1.8.7","com.unity.ugui":"2.0.0","com.unity.visualscripting":"1.9.4","com.unity.modules.accessibility":"1.0.0","com.unity.modules.ai":"1.0.0","com.unity.modules.androidjni":"1.0.0","com.unity.modules.animation":"1.0.0","com.unity.modules.assetbundle":"1.0.0","com.unity.modules.audio":"1.0.0","com.unity.modules.cloth":"1.0.0","com.unity.modules.director":"1.0.0","com.unity.modules.imageconversion":"1.0.0","com.unity.modules.imgui":"1.0.0","com.unity.modules.jsonserialize":"1.0.0","com.unity.modules.particlesystem":"1.0.0","com.unity.modules.physics":"1.0.0","com.unity.modules.physics2d":"1.0.0","com.unity.modules.screencapture":"1.0.0","com.unity.modules.terrain":"1.0.0","com.unity.modules.terrainphysics":"1.0.0","com.unity.modules.tilemap":"1.0.0","com.unity.modules.ui":"1.0.0","com.unity.modules.uielements":"1.0.0","com.unity.modules.umbra":"1.0.0","com.unity.modules.unityanalytics":"1.0.0","com.unity.modules.unitywebrequest":"1.0.0","com.unity.modules.unitywebrequestassetbundle":"1.0.0","com.unity.modules.unitywebrequestaudio":"1.0.0","com.unity.modules.unitywebrequesttexture":"1.0.0","com.unity.modules.unitywebrequestwww":"1.0.0","com.unity.modules.vehicles":"1.0.0","com.unity.modules.video":"1.0.0","com.unity.modules.vr":"1.0.0","com.unity.modules.wind":"1.0.0","com.unity.modules.xr":"1.0.0"}} \ No newline at end of file