From cb01366cb95cdb1c658687f61b9f9454bcb32374 Mon Sep 17 00:00:00 2001 From: snehapar9 Date: Tue, 19 Sep 2023 15:20:00 -0700 Subject: [PATCH] Refactor and test --- .github/workflows/run-validation.yml | 2 - dist/index.js | 374 +++++++++++---------------- index.js | 45 ++-- index.ts | 47 ++-- src/AzureAuthenticationHelper.ts | 40 --- src/CommandHelper.js | 30 ++- src/CommandHelper.ts | 31 ++- src/ContainerAppHelper.js | 127 ++++----- src/ContainerAppHelper.ts | 139 +++------- src/ContainerRegistryHelper.js | 8 +- src/ContainerRegistryHelper.ts | 14 +- src/TelemetryHelper.js | 45 +--- src/TelemetryHelper.ts | 29 +-- src/Utility.js | 121 ++------- src/Utility.ts | 168 ++++-------- 15 files changed, 434 insertions(+), 786 deletions(-) delete mode 100644 src/AzureAuthenticationHelper.ts diff --git a/.github/workflows/run-validation.yml b/.github/workflows/run-validation.yml index 730b394a..9495df46 100644 --- a/.github/workflows/run-validation.yml +++ b/.github/workflows/run-validation.yml @@ -83,7 +83,6 @@ jobs: with: repository: microsoft/Oryx path: oryx - ref: snehapar/Add-libbrotli-dev - name: Log in to Azure uses: azure/login@v1 @@ -131,7 +130,6 @@ jobs: with: repository: microsoft/Oryx path: oryx - ref: snehapar/Add-libbrotli-dev - name: Log in to Azure uses: azure/login@v1 diff --git a/dist/index.js b/dist/index.js index 13e10592..e22affd2 100644 --- a/dist/index.js +++ b/dist/index.js @@ -47,7 +47,6 @@ exports.azurecontainerapps = void 0; var core = __nccwpck_require__(3195); var fs = __nccwpck_require__(7147); var path = __nccwpck_require__(1017); -//import { AzureAuthenticationHelper } from './src/AzureAuthenticationHelper'; var ContainerAppHelper_1 = __nccwpck_require__(2929); var ContainerRegistryHelper_1 = __nccwpck_require__(4769); var TelemetryHelper_1 = __nccwpck_require__(7166); @@ -67,10 +66,6 @@ var azurecontainerapps = /** @class */ (function () { _a.label = 1; case 1: _a.trys.push([1, 8, 9, 11]); - // Get the current working directory - //const cwd: string = core.getInput('cwd'); - //io.mkdirP(cwd); - //exec.exec(`cd ${cwd}`); // Validate that the arguments provided can be used for one of the supported scenarios this.validateSupportedScenarioArguments(); // Set up the Azure CLI to be used for this task @@ -175,15 +170,9 @@ var azurecontainerapps = /** @class */ (function () { return __generator(this, function (_a) { switch (_a.label) { case 0: - // Log in to Azure with the service connection provided - // const connectedService: string = tl.getInput('connectedServiceNameARM', true); - // this.authHelper.loginAzureRM(connectedService); // Set the Azure CLI to dynamically install missing extensions return [4 /*yield*/, util.setAzureCliDynamicInstall()]; case 1: - // Log in to Azure with the service connection provided - // const connectedService: string = tl.getInput('connectedServiceNameARM', true); - // this.authHelper.loginAzureRM(connectedService); // Set the Azure CLI to dynamically install missing extensions _a.sent(); return [2 /*return*/]; @@ -246,7 +235,7 @@ var azurecontainerapps = /** @class */ (function () { containerAppName = "app-" + this.buildId + "-" + this.buildNumber; // Replace all '.' characters with '-' characters in the Container App name containerAppName = containerAppName.replace(/\./gi, "-"); - console.log("Default Container App name: " + containerAppName); + core.info("Default Container App name: " + containerAppName); } return containerAppName; }; @@ -289,7 +278,7 @@ var azurecontainerapps = /** @class */ (function () { resourceGroup = core.getInput('resourceGroup', { required: false }); if (!util.isNullOrEmpty(resourceGroup)) return [3 /*break*/, 3]; resourceGroup = containerAppName + "-rg"; - console.log("Default resource group name: " + resourceGroup); + core.info("Default resource group name: " + resourceGroup); return [4 /*yield*/, this.appHelper.doesResourceGroupExist(resourceGroup)]; case 1: resourceGroupExists = _a.sent(); @@ -325,7 +314,7 @@ var azurecontainerapps = /** @class */ (function () { case 1: existingContainerAppEnvironment = _a.sent(); if (!util.isNullOrEmpty(existingContainerAppEnvironment)) { - console.log("Existing Container App environment found in resource group: " + existingContainerAppEnvironment); + core.info("Existing Container App environment found in resource group: " + existingContainerAppEnvironment); return [2 /*return*/, existingContainerAppEnvironment]; } _a.label = 2; @@ -333,7 +322,7 @@ var azurecontainerapps = /** @class */ (function () { // Generate the Container App environment name if it was not provided if (util.isNullOrEmpty(containerAppEnvironment)) { containerAppEnvironment = containerAppName + "-env"; - console.log("Default Container App environment name: " + containerAppEnvironment); + core.info("Default Container App environment name: " + containerAppEnvironment); } return [4 /*yield*/, this.appHelper.doesContainerAppEnvironmentExist(containerAppEnvironment, resourceGroup)]; case 3: @@ -359,13 +348,13 @@ var azurecontainerapps = /** @class */ (function () { this.acrUsername = core.getInput('acrUsername', { required: false }); this.acrPassword = core.getInput('acrPassword', { required: false }); if (!(!util.isNullOrEmpty(this.acrUsername) && !util.isNullOrEmpty(this.acrPassword))) return [3 /*break*/, 2]; - console.log("Logging in to ACR instance \"" + this.acrName + "\" with username and password credentials"); + core.info("Logging in to ACR instance \"" + this.acrName + "\" with username and password credentials"); return [4 /*yield*/, this.registryHelper.loginAcrWithUsernamePassword(this.acrName, this.acrUsername, this.acrPassword)]; case 1: _a.sent(); return [3 /*break*/, 4]; case 2: - console.log("No ACR credentials provided; attempting to log in to ACR instance \"" + this.acrName + "\" with access token"); + core.info("No ACR credentials provided; attempting to log in to ACR instance \"" + this.acrName + "\" with access token"); return [4 /*yield*/, this.registryHelper.loginAcrWithAccessTokenAsync(this.acrName)]; case 3: _a.sent(); @@ -395,19 +384,19 @@ var azurecontainerapps = /** @class */ (function () { this.imageToBuild = core.getInput('imageToBuild', { required: false }); if (util.isNullOrEmpty(this.imageToBuild)) { this.imageToBuild = this.acrName + ".azurecr.io/ado-task/container-app:" + this.buildId + "." + this.buildNumber; - console.log("Default image to build: " + this.imageToBuild); + core.info("Default image to build: " + this.imageToBuild); } // Get the name of the image to deploy if it was provided, or set it to the value of 'imageToBuild' if (util.isNullOrEmpty(this.imageToDeploy)) { this.imageToDeploy = this.imageToBuild; - console.log("Default image to deploy: " + this.imageToDeploy); + core.info("Default image to deploy: " + this.imageToDeploy); } dockerfilePath = core.getInput('dockerfilePath', { required: false }); if (!util.isNullOrEmpty(dockerfilePath)) return [3 /*break*/, 4]; - console.log("No Dockerfile path provided; checking for Dockerfile at root of application source."); + core.info("No Dockerfile path provided; checking for Dockerfile at root of application source."); rootDockerfilePath = path.join(this.appSourcePath, 'Dockerfile'); if (!fs.existsSync(rootDockerfilePath)) return [3 /*break*/, 1]; - console.log("Dockerfile found at root of application source."); + core.info("Dockerfile found at root of application source."); dockerfilePath = rootDockerfilePath; return [3 /*break*/, 3]; case 1: @@ -456,7 +445,7 @@ var azurecontainerapps = /** @class */ (function () { case 1: // Install the pack CLI _b.sent(); - console.log("Successfully installed the pack CLI."); + core.info("Successfully installed the pack CLI."); // Get the runtime stack if provided, or determine it using Oryx this.runtimeStack = core.getInput('runtimeStack', { required: false }); if (!util.isNullOrEmpty(this.runtimeStack)) return [3 /*break*/, 3]; @@ -467,7 +456,7 @@ var azurecontainerapps = /** @class */ (function () { core.info("Runtime stack determined to be: " + this.runtimeStack); _b.label = 3; case 3: - console.log("Building image \"" + imageToBuild + "\" using the Oryx++ Builder"); + core.info("Building image \"" + imageToBuild + "\" using the Oryx++ Builder"); // Set the Oryx++ Builder as the default builder locally return [4 /*yield*/, this.appHelper.setDefaultBuilder()]; case 4: @@ -496,7 +485,7 @@ var azurecontainerapps = /** @class */ (function () { return __generator(this, function (_a) { switch (_a.label) { case 0: - console.log("Building image \"" + imageToBuild + "\" using the provided Dockerfile"); + core.info("Building image \"" + imageToBuild + "\" using the provided Dockerfile"); return [4 /*yield*/, this.appHelper.createRunnableAppImageFromDockerfile(imageToBuild, appSourcePath, dockerfilePath)]; case 1: _a.sent(); @@ -532,12 +521,12 @@ var azurecontainerapps = /** @class */ (function () { // Set the ingress value to 'external' if it was not provided if (util.isNullOrEmpty(this.ingress)) { this.ingress = 'external'; - console.log("Default ingress value: " + this.ingress); + core.info("Default ingress value: " + this.ingress); } // Set the value of ingressEnabled to 'false' if ingress was provided as 'disabled' if (this.ingress == 'disabled') { this.ingressEnabled = false; - console.log("Ingress is disabled for this Container App."); + core.info("Ingress is disabled for this Container App."); } // Handle setup for ingress values when enabled if (this.ingressEnabled) { @@ -550,12 +539,12 @@ var azurecontainerapps = /** @class */ (function () { else { this.targetPort = '8080'; } - console.log("Default target port: " + this.targetPort); + core.info("Default target port: " + this.targetPort); } // Set the target port to 80 if it was not provided or determined if (util.isNullOrEmpty(this.targetPort)) { this.targetPort = '80'; - console.log("Default target port: " + this.targetPort); + core.info("Default target port: " + this.targetPort); } // Add the ingress value and target port to the optional arguments array // Note: this step should be skipped if we're updating an existing Container App (ingress is enabled via a separate command) @@ -4683,19 +4672,21 @@ var CommandHelper = /** @class */ (function () { */ CommandHelper.prototype.execBashCommandAsync = function (command) { return __awaiter(this, void 0, void 0, function () { - var bashOutput, options, err_1; + var bashOutput, errorStream, options, exitCode, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: bashOutput = ''; + errorStream = ''; options = { listeners: { stdout: function (data) { - process.stdout.write(data); bashOutput += data.toString(); + core.info(data.toString()); }, stderr: function (data) { - process.stderr.write(data); + errorStream += data.toString(); + core.error(data.toString()); } }, failOnStdErr: true, @@ -4708,11 +4699,14 @@ var CommandHelper = /** @class */ (function () { _a.trys.push([1, 3, , 4]); return [4 /*yield*/, exec.exec('bash', ['-c', command], options)]; case 2: - _a.sent(); + exitCode = _a.sent(); + if (exitCode !== 0) { + throw new Error("Command failed with exit code " + exitCode + ". Error stream: " + errorStream); + } return [2 /*return*/, bashOutput.trim()]; case 3: err_1 = _a.sent(); - core.error('Unable to run provided bash command ${command}'); + core.setFailed(err_1.message); throw err_1; case 4: return [2 /*return*/]; } @@ -4726,19 +4720,21 @@ var CommandHelper = /** @class */ (function () { */ CommandHelper.prototype.execPwshCommandAsync = function (command) { return __awaiter(this, void 0, void 0, function () { - var pwshOutput, options, err_2; + var pwshOutput, errorStream, options, exitCode, err_2; return __generator(this, function (_a) { switch (_a.label) { case 0: pwshOutput = ''; + errorStream = ''; options = { listeners: { stdout: function (data) { - process.stdout.write(data); pwshOutput += data.toString(); + core.info(data.toString()); }, stderr: function (data) { - process.stderr.write(data); + errorStream += data.toString(); + core.error(data.toString()); } }, failOnStdErr: true, @@ -4751,11 +4747,14 @@ var CommandHelper = /** @class */ (function () { _a.trys.push([1, 3, , 4]); return [4 /*yield*/, exec.exec('pwsh', [command], options)]; case 2: - _a.sent(); + exitCode = _a.sent(); + if (exitCode !== 0) { + throw new Error("Command failed with exit code " + exitCode + ". Error stream: " + errorStream); + } return [2 /*return*/, pwshOutput.trim()]; case 3: err_2 = _a.sent(); - core.error('Unable to run provided PowerShell command ${command}'); + core.setFailed(err_2.message); throw err_2; case 4: return [2 /*return*/]; } @@ -4813,7 +4812,6 @@ var __generator = (this && this.__generator) || function (thisArg, body) { exports.__esModule = true; exports.ContainerAppHelper = void 0; var core = __nccwpck_require__(3195); -var exec = __nccwpck_require__(9714); var io = __nccwpck_require__(9529); var path = __nccwpck_require__(1017); var os = __nccwpck_require__(2037); @@ -5139,22 +5137,26 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.createResourceGroup = function (name, location) { return __awaiter(this, void 0, void 0, function () { - var command, err_10; - return __generator(this, function (_a) { - switch (_a.label) { + var command, _a, stdout, stderr, err_10; + return __generator(this, function (_b) { + switch (_b.label) { case 0: core.debug("Attempting to create resource group \"" + name + "\" in location \"" + location + "\""); - _a.label = 1; + _b.label = 1; case 1: - _a.trys.push([1, 3, , 4]); + _b.trys.push([1, 3, , 4]); command = "az group create -n " + name + " -l " + location; return [4 /*yield*/, cpExec("" + command)]; case 2: - _a.sent(); + _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; + if (stderr) { + core.error('Failed to create resource group, Error: ' + stderr); + throw new Error(stderr); + } return [3 /*break*/, 4]; case 3: - err_10 = _a.sent(); - core.error(err_10.message); + err_10 = _b.sent(); + core.setFailed(err_10.message); throw err_10; case 4: return [2 /*return*/]; } @@ -5183,7 +5185,7 @@ var ContainerAppHelper = /** @class */ (function () { return [2 /*return*/, !stderr ? stdout : null]; case 3: err_11 = _b.sent(); - core.warning(err_11.message); + core.error(err_11.message); return [2 /*return*/, null]; case 4: return [2 /*return*/]; } @@ -5198,26 +5200,30 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.createContainerAppEnvironment = function (name, resourceGroup, location) { return __awaiter(this, void 0, void 0, function () { - var util, command, err_12; - return __generator(this, function (_a) { - switch (_a.label) { + var util, command, _a, stdout, stderr, err_12; + return __generator(this, function (_b) { + switch (_b.label) { case 0: util = new Utility_1.Utility(); core.debug("Attempting to create Container App Environment with name \"" + name + "\" in resource group \"" + resourceGroup + "\""); - _a.label = 1; + _b.label = 1; case 1: - _a.trys.push([1, 3, , 4]); + _b.trys.push([1, 3, , 4]); command = "az containerapp env create -n " + name + " -g " + resourceGroup; if (!util.isNullOrEmpty(location)) { command += " -l " + location; } return [4 /*yield*/, cpExec("" + command)]; case 2: - _a.sent(); + _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; + if (stderr) { + core.error('Failed to create Container App Environment, Error: ' + stderr); + throw new Error(stderr); + } return [3 /*break*/, 4]; case 3: - err_12 = _a.sent(); - core.error(err_12.message); + err_12 = _b.sent(); + core.setFailed(err_12.message); throw err_12; case 4: return [2 /*return*/]; } @@ -5244,13 +5250,13 @@ var ContainerAppHelper = /** @class */ (function () { case 2: _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; if (stderr) { - core.warning(stderr); + core.error('Failed to disable ingress for Container App, Error: ' + stderr); throw new Error(stderr); } return [3 /*break*/, 4]; case 3: err_13 = _b.sent(); - core.error(err_13.message); + core.setFailed(err_13.message); throw err_13; case 4: return [2 /*return*/]; } @@ -5280,13 +5286,13 @@ var ContainerAppHelper = /** @class */ (function () { case 2: _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; if (stderr) { - core.warning(stderr); + core.error('Failed to set the ACR details for Container App, Error: ' + stderr); throw new Error(stderr); } return [3 /*break*/, 4]; case 3: err_14 = _b.sent(); - core.error(err_14.message); + core.setFailed(err_14.message); throw err_14; case 4: return [2 /*return*/]; } @@ -5301,25 +5307,29 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.createRunnableAppImage = function (imageToDeploy, appSourcePath, runtimeStack) { return __awaiter(this, void 0, void 0, function () { - var telemetryArg, err_15; - return __generator(this, function (_a) { - switch (_a.label) { + var telemetryArg, _a, stdout, stderr, err_15; + return __generator(this, function (_b) { + switch (_b.label) { case 0: core.debug("Attempting to create a runnable application image using the Oryx++ Builder with image name \"" + imageToDeploy + "\""); - _a.label = 1; + _b.label = 1; case 1: - _a.trys.push([1, 3, , 4]); + _b.trys.push([1, 3, , 4]); telemetryArg = "--env \"CALLER_ID=azure-pipelines-rc-v1\""; if (this.disableTelemetry) { telemetryArg = "--env \"ORYX_DISABLE_TELEMETRY=true\""; } return [4 /*yield*/, cpExec(PACK_CMD + " build " + imageToDeploy + " --path " + appSourcePath + " --builder " + ORYX_BUILDER_IMAGE + " --run-image mcr.microsoft.com/oryx/" + runtimeStack + " " + telemetryArg)]; case 2: - _a.sent(); + _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; + if (stderr) { + core.error("Failed to create runnable application image using the Oryx++ Builder with image name \"" + imageToDeploy + "\". Error: " + stderr); + throw new Error(stderr); + } return [3 /*break*/, 4]; case 3: - err_15 = _a.sent(); - core.error(err_15.message); + err_15 = _b.sent(); + core.setFailed(err_15.message); throw err_15; case 4: return [2 /*return*/]; } @@ -5346,14 +5356,14 @@ var ContainerAppHelper = /** @class */ (function () { return [4 /*yield*/, io.which("docker", true)]; case 2: dockerTool = _a.sent(); - return [4 /*yield*/, exec.exec(dockerTool, ['build', '--file', "" + dockerfilePath, "" + appSourcePath, '--tag', "" + imageToDeploy])]; + return [4 /*yield*/, new Utility_1.Utility().executeAndthrowIfError(dockerTool, ['build', '--file', "" + dockerfilePath, "" + appSourcePath, '--tag', "" + imageToDeploy])]; case 3: _a.sent(); - core.info("Successfully created runnable application image from the provided/found Dockerfile \"" + dockerfilePath + "\" with image name \"" + imageToDeploy + "\""); + core.debug("Successfully created runnable application image from the provided/found Dockerfile \"" + dockerfilePath + "\" with image name \"" + imageToDeploy + "\""); return [3 /*break*/, 5]; case 4: err_16 = _a.sent(); - core.error(err_16.message); + core.setFailed(err_16.message); throw err_16; case 5: return [2 /*return*/]; } @@ -5367,7 +5377,7 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.determineRuntimeStackAsync = function (appSourcePath) { return __awaiter(this, void 0, void 0, function () { - var dockerTool, dockerCommand, exitCode, oryxRuntimeTxtPath, command, runtimeStack, err_17; + var dockerTool, oryxRuntimeTxtPath, command, runtimeStack, err_17; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -5378,24 +5388,13 @@ var ContainerAppHelper = /** @class */ (function () { return [4 /*yield*/, io.which("docker", true)]; case 2: dockerTool = _a.sent(); - dockerCommand = "run --rm -v " + appSourcePath + ":/app " + ORYX_CLI_IMAGE + " /bin/bash -c \"oryx dockerfile /app | head -n 1 | sed 's/ARG RUNTIME=//' >> /app/oryx-runtime.txt\""; - return [4 /*yield*/, exec.exec(dockerTool, ['run', '--rm', '-v', appSourcePath + ":/app", "" + ORYX_CLI_IMAGE, '/bin/bash', '-c', "oryx dockerfile /app | head -n 1 | sed 's/ARG RUNTIME=//' >> /app/oryx-runtime.txt"]) - // new Utility().executeAndthrowIfError( - // `${dockerTool}`, - // `${dockerCommand}`, - // `Unable to determine the runtime stack needed for the provided application source.` - // ); + // Use 'oryx dockerfile' command to determine the runtime stack to use and write it to a temp file + return [4 /*yield*/, new Utility_1.Utility().executeAndthrowIfError(dockerTool, ['run', '--rm', '-v', appSourcePath + ":/app", "" + ORYX_CLI_IMAGE, '/bin/bash', '-c', "oryx dockerfile /app | head -n 1 | sed 's/ARG RUNTIME=//' >> /app/oryx-runtime.txt"]) + // Read the temp file to get the runtime stack into a variable ]; case 3: - exitCode = _a.sent(); - // new Utility().executeAndthrowIfError( - // `${dockerTool}`, - // `${dockerCommand}`, - // `Unable to determine the runtime stack needed for the provided application source.` - // ); - if (exitCode != 0) { - throw new Error("Unable to determine the runtime stack needed for the provided application source."); - } + // Use 'oryx dockerfile' command to determine the runtime stack to use and write it to a temp file + _a.sent(); oryxRuntimeTxtPath = path.join(appSourcePath, 'oryx-runtime.txt'); command = "head -n 1 " + oryxRuntimeTxtPath; if (IS_WINDOWS_AGENT) { @@ -5415,7 +5414,7 @@ var ContainerAppHelper = /** @class */ (function () { return [2 /*return*/, runtimeStack]; case 6: err_17 = _a.sent(); - core.error(err_17.message); + core.setFailed(err_17.message); throw err_17; case 7: return [2 /*return*/]; } @@ -5428,21 +5427,25 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.setDefaultBuilder = function () { return __awaiter(this, void 0, void 0, function () { - var err_18; - return __generator(this, function (_a) { - switch (_a.label) { + var _a, stdout, stderr, err_18; + return __generator(this, function (_b) { + switch (_b.label) { case 0: - console.log('Setting the Oryx++ Builder as the default builder via the pack CLI'); - _a.label = 1; + core.info('Setting the Oryx++ Builder as the default builder via the pack CLI'); + _b.label = 1; case 1: - _a.trys.push([1, 3, , 4]); + _b.trys.push([1, 3, , 4]); return [4 /*yield*/, cpExec("pack config default-builder " + ORYX_BUILDER_IMAGE)]; case 2: - _a.sent(); + _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; + if (stderr) { + core.error("Failed to set the Oryx++ Builder as the default builder via the pack CLI. Error: " + stderr); + throw new Error(stderr); + } return [3 /*break*/, 4]; case 3: - err_18 = _a.sent(); - core.error(err_18.message); + err_18 = _b.sent(); + core.setFailed(err_18.message); throw err_18; case 4: return [2 /*return*/]; } @@ -5483,7 +5486,8 @@ var ContainerAppHelper = /** @class */ (function () { return [3 /*break*/, 4]; case 3: err_19 = _a.sent(); - core.error("Unable to install the pack CLI."); + core.error("Unable to install the pack CLI. Error: " + err_19.message); + core.setFailed(err_19.message); throw err_19; case 4: return [2 /*return*/]; } @@ -5544,6 +5548,7 @@ var core = __nccwpck_require__(3195); var exec = __nccwpck_require__(9714); var io = __nccwpck_require__(9529); var CommandHelper_1 = __nccwpck_require__(1988); +var Utility_1 = __nccwpck_require__(2135); var ContainerRegistryHelper = /** @class */ (function () { function ContainerRegistryHelper() { } @@ -5622,15 +5627,14 @@ var ContainerRegistryHelper = /** @class */ (function () { return [4 /*yield*/, io.which("docker", true)]; case 2: dockerTool = _a.sent(); - return [4 /*yield*/, exec.exec(dockerTool, ["push", "" + imageToPush])]; + return [4 /*yield*/, new Utility_1.Utility().executeAndthrowIfError(dockerTool, ["push", "" + imageToPush])]; case 3: _a.sent(); - core.info("Successfully pushed image \"" + imageToPush + "\" to ACR"); return [3 /*break*/, 5]; case 4: err_3 = _a.sent(); - core.error("Failed to push image \"" + imageToPush + "\" to ACR"); - core.error(err_3.message); + core.error("Failed to push image \"" + imageToPush + "\" to ACR. Error: " + err_3.message); + core.setFailed(err_3.message); throw err_3; case 5: return [2 /*return*/]; } @@ -5689,7 +5693,6 @@ exports.__esModule = true; exports.TelemetryHelper = void 0; var core = __nccwpck_require__(3195); var Utility_1 = __nccwpck_require__(2135); -var exec = __nccwpck_require__(9714); var io = __nccwpck_require__(9529); var ORYX_CLI_IMAGE = "mcr.microsoft.com/oryx/cli:debian-buster-20230207.2"; var SUCCESSFUL_RESULT = "succeeded"; @@ -5745,7 +5748,7 @@ var TelemetryHelper = /** @class */ (function () { case 0: taskLengthMilliseconds = Date.now() - this.taskStartMilliseconds; if (!!this.disableTelemetry) return [3 /*break*/, 4]; - core.debug("Telemetry enabled; logging metadata about task result, length and scenario targeted."); + core.info("Telemetry enabled; logging metadata about task result, length and scenario targeted."); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); @@ -5762,13 +5765,9 @@ var TelemetryHelper = /** @class */ (function () { errorMessageArg = "--property 'errorMessage=" + this.errorMessage + "'"; } args = ["run", "--rm", "" + ORYX_CLI_IMAGE, "/bin/bash", "-c", "oryx telemetry --event-name 'ContainerAppsPipelinesTaskRCV1' " + ("--processing-time '" + taskLengthMilliseconds + "' " + resultArg + " " + scenarioArg + " " + errorMessageArg + "\"")]; - // const dockerCommand = `run --rm ${ORYX_CLI_IMAGE} /bin/bash -c "oryx telemetry --event-name 'ContainerAppsPipelinesTaskRCV1' ` + - // `--processing-time '${taskLengthMilliseconds}' ${resultArg} ${scenarioArg} ${errorMessageArg}"` // Don't use Utility's throwIfError() since it will still record an error in the pipeline logs, but won't fail the task return [4 /*yield*/, executeDockerCommand(args, true)]; case 2: - // const dockerCommand = `run --rm ${ORYX_CLI_IMAGE} /bin/bash -c "oryx telemetry --event-name 'ContainerAppsPipelinesTaskRCV1' ` + - // `--processing-time '${taskLengthMilliseconds}' ${resultArg} ${scenarioArg} ${errorMessageArg}"` // Don't use Utility's throwIfError() since it will still record an error in the pipeline logs, but won't fail the task _a.sent(); return [3 /*break*/, 4]; @@ -5787,39 +5786,23 @@ exports.TelemetryHelper = TelemetryHelper; var executeDockerCommand = function (args, continueOnError) { if (continueOnError === void 0) { continueOnError = false; } return __awaiter(void 0, void 0, void 0, function () { - var dockerTool, errorStream, execOptions, exitCode, error_1; + var dockerTool, err_2; return __generator(this, function (_a) { switch (_a.label) { - case 0: return [4 /*yield*/, io.which("docker", true)]; + case 0: + _a.trys.push([0, 3, , 4]); + return [4 /*yield*/, io.which("docker", true)]; case 1: dockerTool = _a.sent(); - errorStream = ''; - execOptions = { - listeners: { - stdout: function (data) { return console.log(data.toString()); } - } - }; - _a.label = 2; + return [4 /*yield*/, new Utility_1.Utility().executeAndthrowIfError(dockerTool, args, continueOnError)]; case 2: - _a.trys.push([2, 4, 5, 6]); - return [4 /*yield*/, exec.exec(dockerTool, args, execOptions)]; + _a.sent(); + return [3 /*break*/, 4]; case 3: - exitCode = _a.sent(); - return [3 /*break*/, 6]; - case 4: - error_1 = _a.sent(); - if (!continueOnError) { - throw error_1; - } - core.warning(error_1); - return [3 /*break*/, 6]; - case 5: - if (exitCode !== 0 && !continueOnError) { - throw new Error(errorStream || 'az cli script failed.'); - } - core.warning(errorStream); - return [7 /*endfinally*/]; - case 6: return [2 /*return*/]; + err_2 = _a.sent(); + core.setFailed("Error: " + err_2.message); + throw err_2; // Re-throw the error + case 4: return [2 /*return*/]; } }); }); @@ -5879,10 +5862,12 @@ var Utility = /** @class */ (function () { function Utility() { } /** - * @param command - the command to execute - * @param errormsg - the error message to display if the command failed + * @param commandLine - the command to execute + * @param args - the arguments to pass to the command + * @param continueOnError - whether or not to continue execution if the command fails */ - Utility.prototype.executeAndthrowIfError = function (commandToolPath, command, errormsg) { + Utility.prototype.executeAndthrowIfError = function (commandLine, args, continueOnError) { + if (continueOnError === void 0) { continueOnError = false; } return __awaiter(this, void 0, void 0, function () { var stdout_1, stderr_1, options, exitCode, error_1; return __generator(this, function (_a) { @@ -5895,21 +5880,20 @@ var Utility = /** @class */ (function () { listeners: { stdout: function (data) { stdout_1 += data.toString(); + core.info(data.toString()); }, stderr: function (data) { stderr_1 += data.toString(); + core.error(data.toString()); } } }; - return [4 /*yield*/, exec.exec(commandToolPath, [command], options)]; + return [4 /*yield*/, exec.exec(commandLine, args, options)]; case 1: exitCode = _a.sent(); - if (exitCode !== 0) { - core.error("Command failed with exit code " + exitCode); - if (errormsg) { - core.error("Error Message: " + errormsg); - } - throw new Error("Command failed with exit code " + exitCode); + if (!continueOnError && exitCode !== 0) { + core.error("Command failed with exit code " + exitCode + ". Error stream: " + stderr_1); + throw new Error("Command failed with exit code " + exitCode + ". Error stream: " + stderr_1); } return [3 /*break*/, 3]; case 2: @@ -5921,38 +5905,27 @@ var Utility = /** @class */ (function () { }); }); }; - Utility.prototype.executeAndReturnExitCode = function (pathToTool, command, errormsg) { + /** + * Sets the Azure CLI to dynamically install extensions that are missing. In this case, we care about the + * Azure Container Apps module being dynamically installed while it's still in preview. + */ + Utility.prototype.setAzureCliDynamicInstall = function () { return __awaiter(this, void 0, void 0, function () { - var stdout_2, stderr_2, options, exitCode, error_2; - return __generator(this, function (_a) { - switch (_a.label) { + var _a, stdout, stderr, error_2; + return __generator(this, function (_b) { + switch (_b.label) { case 0: - _a.trys.push([0, 2, , 3]); - stdout_2 = ''; - stderr_2 = ''; - options = { - listeners: { - stdout: function (data) { - stdout_2 += data.toString(); - }, - stderr: function (data) { - stderr_2 += data.toString(); - } - } - }; - return [4 /*yield*/, exec.exec(pathToTool, [command], options)]; + _b.trys.push([0, 2, , 3]); + return [4 /*yield*/, cpExec("az config set extension.use_dynamic_install=yes_without_prompt")]; case 1: - exitCode = _a.sent(); - if (exitCode !== 0) { - core.error("Command failed with exit code " + exitCode); - if (errormsg) { - core.error("Error Message: " + errormsg); - } - throw new Error("Command failed with exit code " + exitCode); + _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; + if (stderr) { + core.error("Unable to set Azure CLI to dynamically install extensions. Error: " + stderr); + throw new Error("Unable to set Azure CLI to dynamically install extensions. Error: " + stderr); } - return [2 /*return*/, exitCode]; + return [3 /*break*/, 3]; case 2: - error_2 = _a.sent(); + error_2 = _b.sent(); core.setFailed("Error: " + error_2.message); throw error_2; // Re-throw the error case 3: return [2 /*return*/]; @@ -5960,61 +5933,6 @@ var Utility = /** @class */ (function () { }); }); }; - Utility.prototype.executeAndReturnOutput = function (pathToTool, command, errormsg) { - return __awaiter(this, void 0, void 0, function () { - var stdout_3, stderr_3, options, exitCode, error_3; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 2, , 3]); - stdout_3 = ''; - stderr_3 = ''; - options = { - listeners: { - stdout: function (data) { - stdout_3 += data.toString(); - }, - stderr: function (data) { - stderr_3 += data.toString(); - } - } - }; - return [4 /*yield*/, exec.exec(pathToTool, [command], options)]; - case 1: - exitCode = _a.sent(); - if (exitCode !== 0) { - core.error("Command failed with exit code " + exitCode); - if (errormsg) { - core.error("Error Message: " + errormsg); - } - throw new Error("Command failed with exit code " + exitCode); - } - return [2 /*return*/, stdout_3]; - case 2: - error_3 = _a.sent(); - core.setFailed("Error: " + error_3.message); - throw error_3; // Re-throw the error - case 3: return [2 /*return*/]; - } - }); - }); - }; - /** - * Sets the Azure CLI to dynamically install extensions that are missing. In this case, we care about the - * Azure Container Apps module being dynamically installed while it's still in preview. - */ - Utility.prototype.setAzureCliDynamicInstall = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, cpExec("az config set extension.use_dynamic_install=yes_without_prompt")]; - case 1: - _a.sent(); - return [2 /*return*/]; - } - }); - }); - }; /** * Checks whether or not the provided string is null, undefined or empty. * @param str - the string to validate diff --git a/index.js b/index.js index 4c19125a..6c20f819 100644 --- a/index.js +++ b/index.js @@ -40,7 +40,6 @@ exports.azurecontainerapps = void 0; var core = require("@actions/core"); var fs = require("fs"); var path = require("path"); -//import { AzureAuthenticationHelper } from './src/AzureAuthenticationHelper'; var ContainerAppHelper_1 = require("./src/ContainerAppHelper"); var ContainerRegistryHelper_1 = require("./src/ContainerRegistryHelper"); var TelemetryHelper_1 = require("./src/TelemetryHelper"); @@ -60,10 +59,6 @@ var azurecontainerapps = /** @class */ (function () { _a.label = 1; case 1: _a.trys.push([1, 8, 9, 11]); - // Get the current working directory - //const cwd: string = core.getInput('cwd'); - //io.mkdirP(cwd); - //exec.exec(`cd ${cwd}`); // Validate that the arguments provided can be used for one of the supported scenarios this.validateSupportedScenarioArguments(); // Set up the Azure CLI to be used for this task @@ -168,15 +163,9 @@ var azurecontainerapps = /** @class */ (function () { return __generator(this, function (_a) { switch (_a.label) { case 0: - // Log in to Azure with the service connection provided - // const connectedService: string = tl.getInput('connectedServiceNameARM', true); - // this.authHelper.loginAzureRM(connectedService); // Set the Azure CLI to dynamically install missing extensions return [4 /*yield*/, util.setAzureCliDynamicInstall()]; case 1: - // Log in to Azure with the service connection provided - // const connectedService: string = tl.getInput('connectedServiceNameARM', true); - // this.authHelper.loginAzureRM(connectedService); // Set the Azure CLI to dynamically install missing extensions _a.sent(); return [2 /*return*/]; @@ -239,7 +228,7 @@ var azurecontainerapps = /** @class */ (function () { containerAppName = "app-" + this.buildId + "-" + this.buildNumber; // Replace all '.' characters with '-' characters in the Container App name containerAppName = containerAppName.replace(/\./gi, "-"); - console.log("Default Container App name: " + containerAppName); + core.info("Default Container App name: " + containerAppName); } return containerAppName; }; @@ -282,7 +271,7 @@ var azurecontainerapps = /** @class */ (function () { resourceGroup = core.getInput('resourceGroup', { required: false }); if (!util.isNullOrEmpty(resourceGroup)) return [3 /*break*/, 3]; resourceGroup = containerAppName + "-rg"; - console.log("Default resource group name: " + resourceGroup); + core.info("Default resource group name: " + resourceGroup); return [4 /*yield*/, this.appHelper.doesResourceGroupExist(resourceGroup)]; case 1: resourceGroupExists = _a.sent(); @@ -318,7 +307,7 @@ var azurecontainerapps = /** @class */ (function () { case 1: existingContainerAppEnvironment = _a.sent(); if (!util.isNullOrEmpty(existingContainerAppEnvironment)) { - console.log("Existing Container App environment found in resource group: " + existingContainerAppEnvironment); + core.info("Existing Container App environment found in resource group: " + existingContainerAppEnvironment); return [2 /*return*/, existingContainerAppEnvironment]; } _a.label = 2; @@ -326,7 +315,7 @@ var azurecontainerapps = /** @class */ (function () { // Generate the Container App environment name if it was not provided if (util.isNullOrEmpty(containerAppEnvironment)) { containerAppEnvironment = containerAppName + "-env"; - console.log("Default Container App environment name: " + containerAppEnvironment); + core.info("Default Container App environment name: " + containerAppEnvironment); } return [4 /*yield*/, this.appHelper.doesContainerAppEnvironmentExist(containerAppEnvironment, resourceGroup)]; case 3: @@ -352,13 +341,13 @@ var azurecontainerapps = /** @class */ (function () { this.acrUsername = core.getInput('acrUsername', { required: false }); this.acrPassword = core.getInput('acrPassword', { required: false }); if (!(!util.isNullOrEmpty(this.acrUsername) && !util.isNullOrEmpty(this.acrPassword))) return [3 /*break*/, 2]; - console.log("Logging in to ACR instance \"" + this.acrName + "\" with username and password credentials"); + core.info("Logging in to ACR instance \"" + this.acrName + "\" with username and password credentials"); return [4 /*yield*/, this.registryHelper.loginAcrWithUsernamePassword(this.acrName, this.acrUsername, this.acrPassword)]; case 1: _a.sent(); return [3 /*break*/, 4]; case 2: - console.log("No ACR credentials provided; attempting to log in to ACR instance \"" + this.acrName + "\" with access token"); + core.info("No ACR credentials provided; attempting to log in to ACR instance \"" + this.acrName + "\" with access token"); return [4 /*yield*/, this.registryHelper.loginAcrWithAccessTokenAsync(this.acrName)]; case 3: _a.sent(); @@ -388,19 +377,19 @@ var azurecontainerapps = /** @class */ (function () { this.imageToBuild = core.getInput('imageToBuild', { required: false }); if (util.isNullOrEmpty(this.imageToBuild)) { this.imageToBuild = this.acrName + ".azurecr.io/ado-task/container-app:" + this.buildId + "." + this.buildNumber; - console.log("Default image to build: " + this.imageToBuild); + core.info("Default image to build: " + this.imageToBuild); } // Get the name of the image to deploy if it was provided, or set it to the value of 'imageToBuild' if (util.isNullOrEmpty(this.imageToDeploy)) { this.imageToDeploy = this.imageToBuild; - console.log("Default image to deploy: " + this.imageToDeploy); + core.info("Default image to deploy: " + this.imageToDeploy); } dockerfilePath = core.getInput('dockerfilePath', { required: false }); if (!util.isNullOrEmpty(dockerfilePath)) return [3 /*break*/, 4]; - console.log("No Dockerfile path provided; checking for Dockerfile at root of application source."); + core.info("No Dockerfile path provided; checking for Dockerfile at root of application source."); rootDockerfilePath = path.join(this.appSourcePath, 'Dockerfile'); if (!fs.existsSync(rootDockerfilePath)) return [3 /*break*/, 1]; - console.log("Dockerfile found at root of application source."); + core.info("Dockerfile found at root of application source."); dockerfilePath = rootDockerfilePath; return [3 /*break*/, 3]; case 1: @@ -449,7 +438,7 @@ var azurecontainerapps = /** @class */ (function () { case 1: // Install the pack CLI _b.sent(); - console.log("Successfully installed the pack CLI."); + core.info("Successfully installed the pack CLI."); // Get the runtime stack if provided, or determine it using Oryx this.runtimeStack = core.getInput('runtimeStack', { required: false }); if (!util.isNullOrEmpty(this.runtimeStack)) return [3 /*break*/, 3]; @@ -460,7 +449,7 @@ var azurecontainerapps = /** @class */ (function () { core.info("Runtime stack determined to be: " + this.runtimeStack); _b.label = 3; case 3: - console.log("Building image \"" + imageToBuild + "\" using the Oryx++ Builder"); + core.info("Building image \"" + imageToBuild + "\" using the Oryx++ Builder"); // Set the Oryx++ Builder as the default builder locally return [4 /*yield*/, this.appHelper.setDefaultBuilder()]; case 4: @@ -489,7 +478,7 @@ var azurecontainerapps = /** @class */ (function () { return __generator(this, function (_a) { switch (_a.label) { case 0: - console.log("Building image \"" + imageToBuild + "\" using the provided Dockerfile"); + core.info("Building image \"" + imageToBuild + "\" using the provided Dockerfile"); return [4 /*yield*/, this.appHelper.createRunnableAppImageFromDockerfile(imageToBuild, appSourcePath, dockerfilePath)]; case 1: _a.sent(); @@ -525,12 +514,12 @@ var azurecontainerapps = /** @class */ (function () { // Set the ingress value to 'external' if it was not provided if (util.isNullOrEmpty(this.ingress)) { this.ingress = 'external'; - console.log("Default ingress value: " + this.ingress); + core.info("Default ingress value: " + this.ingress); } // Set the value of ingressEnabled to 'false' if ingress was provided as 'disabled' if (this.ingress == 'disabled') { this.ingressEnabled = false; - console.log("Ingress is disabled for this Container App."); + core.info("Ingress is disabled for this Container App."); } // Handle setup for ingress values when enabled if (this.ingressEnabled) { @@ -543,12 +532,12 @@ var azurecontainerapps = /** @class */ (function () { else { this.targetPort = '8080'; } - console.log("Default target port: " + this.targetPort); + core.info("Default target port: " + this.targetPort); } // Set the target port to 80 if it was not provided or determined if (util.isNullOrEmpty(this.targetPort)) { this.targetPort = '80'; - console.log("Default target port: " + this.targetPort); + core.info("Default target port: " + this.targetPort); } // Add the ingress value and target port to the optional arguments array // Note: this step should be skipped if we're updating an existing Container App (ingress is enabled via a separate command) diff --git a/index.ts b/index.ts index 6b2e24f6..ba92c6eb 100644 --- a/index.ts +++ b/index.ts @@ -1,10 +1,6 @@ import * as core from '@actions/core'; -//import * as github from '@actions/github'; -import * as io from '@actions/io'; -import * as exec from '@actions/exec'; import * as fs from 'fs'; import * as path from 'path'; -//import { AzureAuthenticationHelper } from './src/AzureAuthenticationHelper'; import { ContainerAppHelper } from './src/ContainerAppHelper'; import { ContainerRegistryHelper } from './src/ContainerRegistryHelper'; import { TelemetryHelper } from './src/TelemetryHelper'; @@ -19,11 +15,6 @@ export class azurecontainerapps { this.initializeHelpers(disableTelemetry); try { - // Get the current working directory - //const cwd: string = core.getInput('cwd'); - //io.mkdirP(cwd); - //exec.exec(`cd ${cwd}`); - // Validate that the arguments provided can be used for one of the supported scenarios this.validateSupportedScenarioArguments(); @@ -161,10 +152,6 @@ export class azurecontainerapps { * setting the Azure CLI to dynamically install missing extensions. */ private static async setupAzureCli() { - // Log in to Azure with the service connection provided - // const connectedService: string = tl.getInput('connectedServiceNameARM', true); - // this.authHelper.loginAzureRM(connectedService); - // Set the Azure CLI to dynamically install missing extensions await util.setAzureCliDynamicInstall(); } @@ -207,7 +194,7 @@ export class azurecontainerapps { // Replace all '.' characters with '-' characters in the Container App name containerAppName = containerAppName.replace(/\./gi, "-"); - console.log(`Default Container App name: ${containerAppName}`); + core.info(`Default Container App name: ${containerAppName}`); } return containerAppName; @@ -243,7 +230,7 @@ export class azurecontainerapps { let resourceGroup: string = core.getInput('resourceGroup', {required: false}); if (util.isNullOrEmpty(resourceGroup)) { resourceGroup = `${containerAppName}-rg`; - console.log(`Default resource group name: ${resourceGroup}`); + core.info(`Default resource group name: ${resourceGroup}`); // Ensure that the resource group that the Container App will be created in exists const resourceGroupExists = await this.appHelper.doesResourceGroupExist(resourceGroup); @@ -276,7 +263,7 @@ export class azurecontainerapps { if (util.isNullOrEmpty(containerAppEnvironment)) { const existingContainerAppEnvironment: string = await this.appHelper.getExistingContainerAppEnvironment(resourceGroup); if (!util.isNullOrEmpty(existingContainerAppEnvironment)) { - console.log(`Existing Container App environment found in resource group: ${existingContainerAppEnvironment}`); + core.info(`Existing Container App environment found in resource group: ${existingContainerAppEnvironment}`); return existingContainerAppEnvironment } } @@ -284,7 +271,7 @@ export class azurecontainerapps { // Generate the Container App environment name if it was not provided if (util.isNullOrEmpty(containerAppEnvironment)) { containerAppEnvironment = `${containerAppName}-env`; - console.log(`Default Container App environment name: ${containerAppEnvironment}`); + core.info(`Default Container App environment name: ${containerAppEnvironment}`); } // Determine if the Container App environment currently exists and create one if it doesn't @@ -305,10 +292,10 @@ export class azurecontainerapps { // Login to ACR if credentials were provided if (!util.isNullOrEmpty(this.acrUsername) && !util.isNullOrEmpty(this.acrPassword)) { - console.log(`Logging in to ACR instance "${this.acrName}" with username and password credentials`); + core.info(`Logging in to ACR instance "${this.acrName}" with username and password credentials`); await this.registryHelper.loginAcrWithUsernamePassword(this.acrName, this.acrUsername, this.acrPassword); } else { - console.log(`No ACR credentials provided; attempting to log in to ACR instance "${this.acrName}" with access token`); + core.info(`No ACR credentials provided; attempting to log in to ACR instance "${this.acrName}" with access token`); await this.registryHelper.loginAcrWithAccessTokenAsync(this.acrName); } } @@ -329,22 +316,22 @@ export class azurecontainerapps { this.imageToBuild = core.getInput('imageToBuild', {required: false}); if (util.isNullOrEmpty(this.imageToBuild)) { this.imageToBuild = `${this.acrName}.azurecr.io/ado-task/container-app:${this.buildId}.${this.buildNumber}`; - console.log(`Default image to build: ${this.imageToBuild}`); + core.info(`Default image to build: ${this.imageToBuild}`); } // Get the name of the image to deploy if it was provided, or set it to the value of 'imageToBuild' if (util.isNullOrEmpty(this.imageToDeploy)) { this.imageToDeploy = this.imageToBuild; - console.log(`Default image to deploy: ${this.imageToDeploy}`); + core.info(`Default image to deploy: ${this.imageToDeploy}`); } // Get Dockerfile to build, if provided, or check if one exists at the root of the provided application let dockerfilePath: string = core.getInput('dockerfilePath', {required: false}); if (util.isNullOrEmpty(dockerfilePath)) { - console.log(`No Dockerfile path provided; checking for Dockerfile at root of application source.`); + core.info(`No Dockerfile path provided; checking for Dockerfile at root of application source.`); const rootDockerfilePath = path.join(this.appSourcePath, 'Dockerfile'); if (fs.existsSync(rootDockerfilePath)) { - console.log(`Dockerfile found at root of application source.`) + core.info(`Dockerfile found at root of application source.`) dockerfilePath = rootDockerfilePath; } else { // No Dockerfile found or provided, build the image using the builder @@ -371,7 +358,7 @@ export class azurecontainerapps { private static async buildImageFromBuilderAsync(appSourcePath: string, imageToBuild: string) { // Install the pack CLI await this.appHelper.installPackCliAsync(); - console.log(`Successfully installed the pack CLI.`) + core.info(`Successfully installed the pack CLI.`) // Get the runtime stack if provided, or determine it using Oryx this.runtimeStack = core.getInput('runtimeStack', {required: false}); @@ -380,7 +367,7 @@ export class azurecontainerapps { core.info(`Runtime stack determined to be: ${this.runtimeStack}`); } - console.log(`Building image "${imageToBuild}" using the Oryx++ Builder`); + core.info(`Building image "${imageToBuild}" using the Oryx++ Builder`); // Set the Oryx++ Builder as the default builder locally await this.appHelper.setDefaultBuilder(); @@ -399,7 +386,7 @@ export class azurecontainerapps { * @param imageToBuild - The name of the image to build. */ private static async builderImageFromDockerfile(appSourcePath: string, dockerfilePath: string, imageToBuild: string) { - console.log(`Building image "${imageToBuild}" using the provided Dockerfile`); + core.info(`Building image "${imageToBuild}" using the provided Dockerfile`); await this.appHelper.createRunnableAppImageFromDockerfile(imageToBuild, appSourcePath, dockerfilePath); // If telemetry is enabled, log that the Dockerfile scenario was targeted for this task @@ -439,13 +426,13 @@ export class azurecontainerapps { // Set the ingress value to 'external' if it was not provided if (util.isNullOrEmpty(this.ingress)) { this.ingress = 'external'; - console.log(`Default ingress value: ${this.ingress}`); + core.info(`Default ingress value: ${this.ingress}`); } // Set the value of ingressEnabled to 'false' if ingress was provided as 'disabled' if (this.ingress == 'disabled') { this.ingressEnabled = false; - console.log(`Ingress is disabled for this Container App.`); + core.info(`Ingress is disabled for this Container App.`); } // Handle setup for ingress values when enabled @@ -459,13 +446,13 @@ export class azurecontainerapps { this.targetPort = '8080'; } - console.log(`Default target port: ${this.targetPort}`); + core.info(`Default target port: ${this.targetPort}`); } // Set the target port to 80 if it was not provided or determined if (util.isNullOrEmpty(this.targetPort)) { this.targetPort = '80'; - console.log(`Default target port: ${this.targetPort}`); + core.info(`Default target port: ${this.targetPort}`); } // Add the ingress value and target port to the optional arguments array diff --git a/src/AzureAuthenticationHelper.ts b/src/AzureAuthenticationHelper.ts deleted file mode 100644 index 2be88116..00000000 --- a/src/AzureAuthenticationHelper.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as core from '@actions/core'; -import * as exec from '@actions/exec'; -import * as io from '@actions/io'; -import * as fs from 'fs'; -import { Utility } from './Utility'; - -export class AzureAuthenticationHelper { - - private sessionLoggedIn: boolean = false; - private cliPasswordPath: string = null; - - /** - * Re-uses the loginAzureRM code implemented by the AzureCLIV2 Azure DevOps Task. - * https://github.com/microsoft/azure-pipelines-tasks/blob/b82a8e69eb862d1a9d291af70da2e62ee69270df/Tasks/AzureCLIV2/azureclitask.ts#L106-L150 - * @param connectedService - an Azure DevOps Service Connection that can authorize the connection to Azure - */ - - - /** - * Re-uses the logoutAzure code implemented by the AzureCLIV2 Azure DevOps Task. - * https://github.com/microsoft/azure-pipelines-tasks/blob/b82a8e69eb862d1a9d291af70da2e62ee69270df/Tasks/AzureCLIV2/azureclitask.ts#L175-L183 - */ - public logoutAzure() { - if (this.cliPasswordPath) { - core.debug('Removing spn certificate file'); - io.rmRF(this.cliPasswordPath); // Remove the certificate file - } - - if (this.sessionLoggedIn) { - core.debug('Attempting to log out from Azure'); - try { - exec.exec('az account clear') - } catch (err) { - // task should not fail if logout doesn`t occur - core.warning(`The following error occurred while logging out: ${err.message}`); - } - } - } -} - diff --git a/src/CommandHelper.js b/src/CommandHelper.js index 79fc1c96..8c8648e5 100644 --- a/src/CommandHelper.js +++ b/src/CommandHelper.js @@ -74,19 +74,21 @@ var CommandHelper = /** @class */ (function () { */ CommandHelper.prototype.execBashCommandAsync = function (command) { return __awaiter(this, void 0, void 0, function () { - var bashOutput, options, err_1; + var bashOutput, errorStream, options, exitCode, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: bashOutput = ''; + errorStream = ''; options = { listeners: { stdout: function (data) { - process.stdout.write(data); bashOutput += data.toString(); + core.info(data.toString()); }, stderr: function (data) { - process.stderr.write(data); + errorStream += data.toString(); + core.error(data.toString()); } }, failOnStdErr: true, @@ -99,11 +101,14 @@ var CommandHelper = /** @class */ (function () { _a.trys.push([1, 3, , 4]); return [4 /*yield*/, exec.exec('bash', ['-c', command], options)]; case 2: - _a.sent(); + exitCode = _a.sent(); + if (exitCode !== 0) { + throw new Error("Command failed with exit code " + exitCode + ". Error stream: " + errorStream); + } return [2 /*return*/, bashOutput.trim()]; case 3: err_1 = _a.sent(); - core.error('Unable to run provided bash command ${command}'); + core.setFailed(err_1.message); throw err_1; case 4: return [2 /*return*/]; } @@ -117,19 +122,21 @@ var CommandHelper = /** @class */ (function () { */ CommandHelper.prototype.execPwshCommandAsync = function (command) { return __awaiter(this, void 0, void 0, function () { - var pwshOutput, options, err_2; + var pwshOutput, errorStream, options, exitCode, err_2; return __generator(this, function (_a) { switch (_a.label) { case 0: pwshOutput = ''; + errorStream = ''; options = { listeners: { stdout: function (data) { - process.stdout.write(data); pwshOutput += data.toString(); + core.info(data.toString()); }, stderr: function (data) { - process.stderr.write(data); + errorStream += data.toString(); + core.error(data.toString()); } }, failOnStdErr: true, @@ -142,11 +149,14 @@ var CommandHelper = /** @class */ (function () { _a.trys.push([1, 3, , 4]); return [4 /*yield*/, exec.exec('pwsh', [command], options)]; case 2: - _a.sent(); + exitCode = _a.sent(); + if (exitCode !== 0) { + throw new Error("Command failed with exit code " + exitCode + ". Error stream: " + errorStream); + } return [2 /*return*/, pwshOutput.trim()]; case 3: err_2 = _a.sent(); - core.error('Unable to run provided PowerShell command ${command}'); + core.setFailed(err_2.message); throw err_2; case 4: return [2 /*return*/]; } diff --git a/src/CommandHelper.ts b/src/CommandHelper.ts index a203b96a..5b23649e 100644 --- a/src/CommandHelper.ts +++ b/src/CommandHelper.ts @@ -1,7 +1,6 @@ import * as os from 'os' import * as core from '@actions/core'; import * as exec from '@actions/exec'; -import * as io from '@actions/io'; export class CommandHelper { @@ -12,8 +11,8 @@ export class CommandHelper { */ public async execCommandAsync(command: string): Promise { return os.platform() == 'win32' ? - await this.execPwshCommandAsync(command) : - await this.execBashCommandAsync(command); + await this.execPwshCommandAsync(command) : + await this.execBashCommandAsync(command); } /** @@ -22,15 +21,17 @@ export class CommandHelper { */ private async execBashCommandAsync(command: string): Promise { var bashOutput: string = ''; + var errorStream: string = ''; const options: any = { listeners: { stdout: (data: Buffer) => { - process.stdout.write(data); bashOutput += data.toString(); + core.info(data.toString()); }, stderr: (data: Buffer) => { - process.stderr.write(data); + errorStream += data.toString(); + core.error(data.toString()); } }, failOnStdErr: true, @@ -39,10 +40,13 @@ export class CommandHelper { outStream: process.stdout, } try { - await exec.exec('bash', ['-c', command], options); + var exitCode = await exec.exec('bash', ['-c', command], options); + if (exitCode !== 0) { + throw new Error(`Command failed with exit code ${exitCode}. Error stream: ${errorStream}`); + } return bashOutput.trim(); } catch (err) { - core.error('Unable to run provided bash command ${command}'); + core.setFailed(err.message); throw err; } } @@ -54,14 +58,16 @@ export class CommandHelper { */ private async execPwshCommandAsync(command: string): Promise { var pwshOutput: string = ''; + var errorStream: string = ''; const options: any = { listeners: { stdout: (data: Buffer) => { - process.stdout.write(data); pwshOutput += data.toString(); + core.info(data.toString()); }, stderr: (data: Buffer) => { - process.stderr.write(data); + errorStream += data.toString(); + core.error(data.toString()); } }, failOnStdErr: true, @@ -70,10 +76,13 @@ export class CommandHelper { outStream: process.stdout, } try { - await exec.exec('pwsh',[command], options); + var exitCode = await exec.exec('pwsh', [command], options); + if (exitCode !== 0) { + throw new Error(`Command failed with exit code ${exitCode}. Error stream: ${errorStream}`); + } return pwshOutput.trim(); } catch (err) { - core.error('Unable to run provided PowerShell command ${command}'); + core.setFailed(err.message); throw err; } } diff --git a/src/ContainerAppHelper.js b/src/ContainerAppHelper.js index 534c6f43..142233a7 100644 --- a/src/ContainerAppHelper.js +++ b/src/ContainerAppHelper.js @@ -38,7 +38,6 @@ var __generator = (this && this.__generator) || function (thisArg, body) { exports.__esModule = true; exports.ContainerAppHelper = void 0; var core = require("@actions/core"); -var exec = require("@actions/exec"); var io = require("@actions/io"); var path = require("path"); var os = require("os"); @@ -364,22 +363,26 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.createResourceGroup = function (name, location) { return __awaiter(this, void 0, void 0, function () { - var command, err_10; - return __generator(this, function (_a) { - switch (_a.label) { + var command, _a, stdout, stderr, err_10; + return __generator(this, function (_b) { + switch (_b.label) { case 0: core.debug("Attempting to create resource group \"" + name + "\" in location \"" + location + "\""); - _a.label = 1; + _b.label = 1; case 1: - _a.trys.push([1, 3, , 4]); + _b.trys.push([1, 3, , 4]); command = "az group create -n " + name + " -l " + location; return [4 /*yield*/, cpExec("" + command)]; case 2: - _a.sent(); + _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; + if (stderr) { + core.error('Failed to create resource group, Error: ' + stderr); + throw new Error(stderr); + } return [3 /*break*/, 4]; case 3: - err_10 = _a.sent(); - core.error(err_10.message); + err_10 = _b.sent(); + core.setFailed(err_10.message); throw err_10; case 4: return [2 /*return*/]; } @@ -408,7 +411,7 @@ var ContainerAppHelper = /** @class */ (function () { return [2 /*return*/, !stderr ? stdout : null]; case 3: err_11 = _b.sent(); - core.warning(err_11.message); + core.error(err_11.message); return [2 /*return*/, null]; case 4: return [2 /*return*/]; } @@ -423,26 +426,30 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.createContainerAppEnvironment = function (name, resourceGroup, location) { return __awaiter(this, void 0, void 0, function () { - var util, command, err_12; - return __generator(this, function (_a) { - switch (_a.label) { + var util, command, _a, stdout, stderr, err_12; + return __generator(this, function (_b) { + switch (_b.label) { case 0: util = new Utility_1.Utility(); core.debug("Attempting to create Container App Environment with name \"" + name + "\" in resource group \"" + resourceGroup + "\""); - _a.label = 1; + _b.label = 1; case 1: - _a.trys.push([1, 3, , 4]); + _b.trys.push([1, 3, , 4]); command = "az containerapp env create -n " + name + " -g " + resourceGroup; if (!util.isNullOrEmpty(location)) { command += " -l " + location; } return [4 /*yield*/, cpExec("" + command)]; case 2: - _a.sent(); + _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; + if (stderr) { + core.error('Failed to create Container App Environment, Error: ' + stderr); + throw new Error(stderr); + } return [3 /*break*/, 4]; case 3: - err_12 = _a.sent(); - core.error(err_12.message); + err_12 = _b.sent(); + core.setFailed(err_12.message); throw err_12; case 4: return [2 /*return*/]; } @@ -469,13 +476,13 @@ var ContainerAppHelper = /** @class */ (function () { case 2: _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; if (stderr) { - core.warning(stderr); + core.error('Failed to disable ingress for Container App, Error: ' + stderr); throw new Error(stderr); } return [3 /*break*/, 4]; case 3: err_13 = _b.sent(); - core.error(err_13.message); + core.setFailed(err_13.message); throw err_13; case 4: return [2 /*return*/]; } @@ -505,13 +512,13 @@ var ContainerAppHelper = /** @class */ (function () { case 2: _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; if (stderr) { - core.warning(stderr); + core.error('Failed to set the ACR details for Container App, Error: ' + stderr); throw new Error(stderr); } return [3 /*break*/, 4]; case 3: err_14 = _b.sent(); - core.error(err_14.message); + core.setFailed(err_14.message); throw err_14; case 4: return [2 /*return*/]; } @@ -526,25 +533,29 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.createRunnableAppImage = function (imageToDeploy, appSourcePath, runtimeStack) { return __awaiter(this, void 0, void 0, function () { - var telemetryArg, err_15; - return __generator(this, function (_a) { - switch (_a.label) { + var telemetryArg, _a, stdout, stderr, err_15; + return __generator(this, function (_b) { + switch (_b.label) { case 0: core.debug("Attempting to create a runnable application image using the Oryx++ Builder with image name \"" + imageToDeploy + "\""); - _a.label = 1; + _b.label = 1; case 1: - _a.trys.push([1, 3, , 4]); + _b.trys.push([1, 3, , 4]); telemetryArg = "--env \"CALLER_ID=azure-pipelines-rc-v1\""; if (this.disableTelemetry) { telemetryArg = "--env \"ORYX_DISABLE_TELEMETRY=true\""; } return [4 /*yield*/, cpExec(PACK_CMD + " build " + imageToDeploy + " --path " + appSourcePath + " --builder " + ORYX_BUILDER_IMAGE + " --run-image mcr.microsoft.com/oryx/" + runtimeStack + " " + telemetryArg)]; case 2: - _a.sent(); + _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; + if (stderr) { + core.error("Failed to create runnable application image using the Oryx++ Builder with image name \"" + imageToDeploy + "\". Error: " + stderr); + throw new Error(stderr); + } return [3 /*break*/, 4]; case 3: - err_15 = _a.sent(); - core.error(err_15.message); + err_15 = _b.sent(); + core.setFailed(err_15.message); throw err_15; case 4: return [2 /*return*/]; } @@ -571,14 +582,14 @@ var ContainerAppHelper = /** @class */ (function () { return [4 /*yield*/, io.which("docker", true)]; case 2: dockerTool = _a.sent(); - return [4 /*yield*/, exec.exec(dockerTool, ['build', '--file', "" + dockerfilePath, "" + appSourcePath, '--tag', "" + imageToDeploy])]; + return [4 /*yield*/, new Utility_1.Utility().executeAndthrowIfError(dockerTool, ['build', '--file', "" + dockerfilePath, "" + appSourcePath, '--tag', "" + imageToDeploy])]; case 3: _a.sent(); - core.info("Successfully created runnable application image from the provided/found Dockerfile \"" + dockerfilePath + "\" with image name \"" + imageToDeploy + "\""); + core.debug("Successfully created runnable application image from the provided/found Dockerfile \"" + dockerfilePath + "\" with image name \"" + imageToDeploy + "\""); return [3 /*break*/, 5]; case 4: err_16 = _a.sent(); - core.error(err_16.message); + core.setFailed(err_16.message); throw err_16; case 5: return [2 /*return*/]; } @@ -592,7 +603,7 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.determineRuntimeStackAsync = function (appSourcePath) { return __awaiter(this, void 0, void 0, function () { - var dockerTool, dockerCommand, exitCode, oryxRuntimeTxtPath, command, runtimeStack, err_17; + var dockerTool, oryxRuntimeTxtPath, command, runtimeStack, err_17; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -603,24 +614,13 @@ var ContainerAppHelper = /** @class */ (function () { return [4 /*yield*/, io.which("docker", true)]; case 2: dockerTool = _a.sent(); - dockerCommand = "run --rm -v " + appSourcePath + ":/app " + ORYX_CLI_IMAGE + " /bin/bash -c \"oryx dockerfile /app | head -n 1 | sed 's/ARG RUNTIME=//' >> /app/oryx-runtime.txt\""; - return [4 /*yield*/, exec.exec(dockerTool, ['run', '--rm', '-v', appSourcePath + ":/app", "" + ORYX_CLI_IMAGE, '/bin/bash', '-c', "oryx dockerfile /app | head -n 1 | sed 's/ARG RUNTIME=//' >> /app/oryx-runtime.txt"]) - // new Utility().executeAndthrowIfError( - // `${dockerTool}`, - // `${dockerCommand}`, - // `Unable to determine the runtime stack needed for the provided application source.` - // ); + // Use 'oryx dockerfile' command to determine the runtime stack to use and write it to a temp file + return [4 /*yield*/, new Utility_1.Utility().executeAndthrowIfError(dockerTool, ['run', '--rm', '-v', appSourcePath + ":/app", "" + ORYX_CLI_IMAGE, '/bin/bash', '-c', "oryx dockerfile /app | head -n 1 | sed 's/ARG RUNTIME=//' >> /app/oryx-runtime.txt"]) + // Read the temp file to get the runtime stack into a variable ]; case 3: - exitCode = _a.sent(); - // new Utility().executeAndthrowIfError( - // `${dockerTool}`, - // `${dockerCommand}`, - // `Unable to determine the runtime stack needed for the provided application source.` - // ); - if (exitCode != 0) { - throw new Error("Unable to determine the runtime stack needed for the provided application source."); - } + // Use 'oryx dockerfile' command to determine the runtime stack to use and write it to a temp file + _a.sent(); oryxRuntimeTxtPath = path.join(appSourcePath, 'oryx-runtime.txt'); command = "head -n 1 " + oryxRuntimeTxtPath; if (IS_WINDOWS_AGENT) { @@ -640,7 +640,7 @@ var ContainerAppHelper = /** @class */ (function () { return [2 /*return*/, runtimeStack]; case 6: err_17 = _a.sent(); - core.error(err_17.message); + core.setFailed(err_17.message); throw err_17; case 7: return [2 /*return*/]; } @@ -653,21 +653,25 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.setDefaultBuilder = function () { return __awaiter(this, void 0, void 0, function () { - var err_18; - return __generator(this, function (_a) { - switch (_a.label) { + var _a, stdout, stderr, err_18; + return __generator(this, function (_b) { + switch (_b.label) { case 0: - console.log('Setting the Oryx++ Builder as the default builder via the pack CLI'); - _a.label = 1; + core.info('Setting the Oryx++ Builder as the default builder via the pack CLI'); + _b.label = 1; case 1: - _a.trys.push([1, 3, , 4]); + _b.trys.push([1, 3, , 4]); return [4 /*yield*/, cpExec("pack config default-builder " + ORYX_BUILDER_IMAGE)]; case 2: - _a.sent(); + _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; + if (stderr) { + core.error("Failed to set the Oryx++ Builder as the default builder via the pack CLI. Error: " + stderr); + throw new Error(stderr); + } return [3 /*break*/, 4]; case 3: - err_18 = _a.sent(); - core.error(err_18.message); + err_18 = _b.sent(); + core.setFailed(err_18.message); throw err_18; case 4: return [2 /*return*/]; } @@ -708,7 +712,8 @@ var ContainerAppHelper = /** @class */ (function () { return [3 /*break*/, 4]; case 3: err_19 = _a.sent(); - core.error("Unable to install the pack CLI."); + core.error("Unable to install the pack CLI. Error: " + err_19.message); + core.setFailed(err_19.message); throw err_19; case 4: return [2 /*return*/]; } diff --git a/src/ContainerAppHelper.ts b/src/ContainerAppHelper.ts index b108c1f4..c0f4309b 100644 --- a/src/ContainerAppHelper.ts +++ b/src/ContainerAppHelper.ts @@ -1,5 +1,4 @@ import * as core from '@actions/core'; -import * as exec from '@actions/exec' import * as io from '@actions/io'; import * as path from 'path'; import * as os from 'os'; @@ -7,8 +6,6 @@ import { CommandHelper } from './CommandHelper'; import { Utility } from './Utility'; const util = require('util'); const cpExec = util.promisify(require('child_process').exec); -import { pathToFileURL } from 'url'; -import { cp } from 'fs'; const ORYX_CLI_IMAGE: string = 'mcr.microsoft.com/oryx/cli:builder-debian-buster-20230208.1'; const ORYX_BUILDER_IMAGE: string = 'mcr.microsoft.com/oryx/builder:20230208.1'; @@ -63,11 +60,6 @@ export class ContainerAppHelper { try { let command = `az containerapp create -n ${containerAppName} -g ${resourceGroup} --yaml ${yamlConfigPath}`; await cpExec(`${command}`); - // new Utility().executeAndthrowIfError( - // await io.which('az', true), - // command, - // "Unable to create Azure Container App from YAML configuration file via 'az containerapp create' command." - // ); } catch (err) { core.error(err.message); throw err; @@ -98,13 +90,6 @@ export class ContainerAppHelper { core.warning(stderr); throw new Error(stderr); } - // const pathToTool = await io.which('az', true); - - // new Utility().executeAndthrowIfError( - // pathToTool, - // command, - // "Unable to update Azure Container App via 'az containerapp update' command." - // ); } catch (err) { core.error(err.message); throw err; @@ -148,14 +133,6 @@ export class ContainerAppHelper { core.warning(stderr); throw new Error(stderr); } - - // const pathToTool = await io.which('az', true); - - // util.executeAndthrowIfError( - // pathToTool, - // command, - // "Unable to update Azure Container App via 'az containerapp up' command." - // ); } catch (err) { core.error(err.message); throw err; @@ -180,12 +157,6 @@ export class ContainerAppHelper { core.warning(stderr); throw new Error(stderr); } - // const pathToTool = await io.which('az', true); - // new Utility().executeAndthrowIfError( - // pathToTool, - // command, - // "Unable to update Azure Container App from YAML configuration file via 'az containerapp update' command." - // ); } catch (err) { core.error(err.message); throw err; @@ -222,9 +193,6 @@ export class ContainerAppHelper { const command = `az containerapp env show -n ${containerAppEnvironment} -g ${resourceGroup} -o none`; const {stdout, stderr} = await cpExec(`${command}`); return !stderr; - // const pathToTool = await io.which('az', true); - // const result = await new Utility().executeAndReturnExitCode(pathToTool, command); - // return result == 0; } catch (err) { core.warning(err.message); return false; @@ -242,9 +210,6 @@ export class ContainerAppHelper { const command = `az group show -n ${resourceGroup} -o none`; const {stdout, stderr} = await cpExec(`${command}`); return !stderr; - // const pathToTool = await io.which('az', true); - // const result = await new Utility().executeAndReturnExitCode(pathToTool, command); - // return result == 0; } catch (err) { core.warning(err.message); return false; @@ -277,9 +242,13 @@ export class ContainerAppHelper { core.debug(`Attempting to create resource group "${name}" in location "${location}"`); try { const command = `az group create -n ${name} -l ${location}`; - await cpExec(`${command}`); + const {stdout, stderr} = await cpExec(`${command}`); + if (stderr) { + core.error('Failed to create resource group, Error: ' + stderr); + throw new Error(stderr); + } } catch (err) { - core.error(err.message); + core.setFailed(err.message); throw err; } } @@ -295,16 +264,8 @@ export class ContainerAppHelper { const command = `az containerapp env list -g ${resourceGroup} --query [0].name"`; const {stdout, stderr} = await cpExec(`${command}`); return !stderr ? stdout : null; - // const pathToTool = await io.which('az', true); - // const result = await new Utility().executeAndReturnExitCode( - // pathToTool, - // command, - // `Unable to get the existing Container App Environment in resource group "${resourceGroup}".` - // ); - // const output = await new Utility().executeAndReturnOutput(pathToTool, command); - // return result == 0 ? output : null; } catch (err) { - core.warning(err.message); + core.error(err.message); return null; } } @@ -323,9 +284,13 @@ export class ContainerAppHelper { if (!util.isNullOrEmpty(location)) { command += ` -l ${location}`; } - await cpExec(`${command}`); + const {stdout, stderr} = await cpExec(`${command}`); + if (stderr) { + core.error('Failed to create Container App Environment, Error: ' + stderr); + throw new Error(stderr); + } } catch (err) { - core.error(err.message); + core.setFailed(err.message); throw err; } } @@ -341,17 +306,11 @@ export class ContainerAppHelper { const command = `az containerapp ingress disable -n ${name} -g ${resourceGroup}`; const {stdout, stderr} = await cpExec(`${command}`); if (stderr) { - core.warning(stderr); + core.error('Failed to disable ingress for Container App, Error: ' + stderr); throw new Error(stderr); } - - // new Utility().executeAndthrowIfError( - // await io.which('az', true), - // command, - // `Unable to disable ingress for Container App via 'az containerapp ingress disable' command.` - // ); } catch (err) { - core.error(err.message); + core.setFailed(err.message); throw err; } } @@ -370,17 +329,11 @@ export class ContainerAppHelper { const command = `az containerapp registry set -n ${name} -g ${resourceGroup} --server ${acrName}.azurecr.io --username ${acrUsername} --password ${acrPassword}`; const {stdout, stderr} = await cpExec(`${command}`); if (stderr) { - core.warning(stderr); + core.error('Failed to set the ACR details for Container App, Error: ' + stderr); throw new Error(stderr); } - // const pathToTool = await io.which('az', true); - // new Utility().executeAndthrowIfError( - // pathToTool, - // command, - // `Unable to set the ACR details for Container App via 'az containerapp registry set' command.` - // ); } catch (err) { - core.error(err.message); + core.setFailed(err.message); throw err; } } @@ -401,15 +354,13 @@ export class ContainerAppHelper { if (this.disableTelemetry) { telemetryArg = `--env "ORYX_DISABLE_TELEMETRY=true"`; } - await cpExec(`${PACK_CMD} build ${imageToDeploy} --path ${appSourcePath} --builder ${ORYX_BUILDER_IMAGE} --run-image mcr.microsoft.com/oryx/${runtimeStack} ${telemetryArg}`); - - // new Utility().executeAndthrowIfError( - // `${PACK_CMD}`, - // `build ${imageToDeploy} --path ${appSourcePath} --builder ${ORYX_BUILDER_IMAGE} --run-image mcr.microsoft.com/oryx/${runtimeStack} ${telemetryArg}`, - // `Unable to create runnable application image using the Oryx++ Builder with image name "${imageToDeploy}".` - // ); + const {stdout, stderr} = await cpExec(`${PACK_CMD} build ${imageToDeploy} --path ${appSourcePath} --builder ${ORYX_BUILDER_IMAGE} --run-image mcr.microsoft.com/oryx/${runtimeStack} ${telemetryArg}`); + if (stderr) { + core.error(`Failed to create runnable application image using the Oryx++ Builder with image name "${imageToDeploy}". Error: ${stderr}`); + throw new Error(stderr); + } } catch (err) { - core.error(err.message); + core.setFailed(err.message); throw err; } } @@ -428,10 +379,10 @@ export class ContainerAppHelper { core.debug(`Attempting to create a runnable application image from the provided/found Dockerfile "${dockerfilePath}" with image name "${imageToDeploy}"`); try { const dockerTool = await io.which("docker", true); - await exec.exec(dockerTool, ['build', '--file', `${dockerfilePath}`, `${appSourcePath}`, '--tag', `${imageToDeploy}`]) - core.info(`Successfully created runnable application image from the provided/found Dockerfile "${dockerfilePath}" with image name "${imageToDeploy}"`); + await new Utility().executeAndthrowIfError(dockerTool, ['build', '--file', `${dockerfilePath}`, `${appSourcePath}`, '--tag', `${imageToDeploy}`]); + core.debug(`Successfully created runnable application image from the provided/found Dockerfile "${dockerfilePath}" with image name "${imageToDeploy}"`); } catch (err) { - core.error(err.message); + core.setFailed(err.message); throw err; } } @@ -446,16 +397,7 @@ export class ContainerAppHelper { try { const dockerTool: string = await io.which("docker", true); // Use 'oryx dockerfile' command to determine the runtime stack to use and write it to a temp file - const dockerCommand: string = `run --rm -v ${appSourcePath}:/app ${ORYX_CLI_IMAGE} /bin/bash -c "oryx dockerfile /app | head -n 1 | sed 's/ARG RUNTIME=//' >> /app/oryx-runtime.txt"`; - const exitCode = await exec.exec(dockerTool, ['run', '--rm', '-v', `${appSourcePath}:/app`, `${ORYX_CLI_IMAGE}`, '/bin/bash', '-c', `oryx dockerfile /app | head -n 1 | sed 's/ARG RUNTIME=//' >> /app/oryx-runtime.txt`]) - // new Utility().executeAndthrowIfError( - // `${dockerTool}`, - // `${dockerCommand}`, - // `Unable to determine the runtime stack needed for the provided application source.` - // ); - if (exitCode != 0) { - throw new Error(`Unable to determine the runtime stack needed for the provided application source.`); - } + await new Utility().executeAndthrowIfError(dockerTool, ['run', '--rm', '-v', `${appSourcePath}:/app`, `${ORYX_CLI_IMAGE}`, '/bin/bash', '-c', `oryx dockerfile /app | head -n 1 | sed 's/ARG RUNTIME=//' >> /app/oryx-runtime.txt`]) // Read the temp file to get the runtime stack into a variable const oryxRuntimeTxtPath = path.join(appSourcePath, 'oryx-runtime.txt'); @@ -476,7 +418,7 @@ export class ContainerAppHelper { return runtimeStack; } catch (err) { - core.error(err.message); + core.setFailed(err.message); throw err; } } @@ -486,17 +428,17 @@ export class ContainerAppHelper { * to no default builder set. */ public async setDefaultBuilder() { - console.log('Setting the Oryx++ Builder as the default builder via the pack CLI'); - try { - await cpExec(`pack config default-builder ${ORYX_BUILDER_IMAGE}`); - // new Utility().executeAndthrowIfError( - // `pack`, - // `config default-builder ${ORYX_BUILDER_IMAGE}`, - // `Unable to set the Oryx++ Builder as the default builder via the pack CLI.` - // ); - - } catch (err) { - core.error(err.message); + core.info('Setting the Oryx++ Builder as the default builder via the pack CLI'); + try + { + const {stdout, stderr} = await cpExec(`pack config default-builder ${ORYX_BUILDER_IMAGE}`); + if (stderr) { + core.error(`Failed to set the Oryx++ Builder as the default builder via the pack CLI. Error: ${stderr}`); + throw new Error(stderr); + } + } + catch (err) { + core.setFailed(err.message); throw err; } } @@ -524,7 +466,8 @@ export class ContainerAppHelper { } await new CommandHelper().execCommandAsync(command); } catch (err) { - core.error(`Unable to install the pack CLI.`) + core.error(`Unable to install the pack CLI. Error: ${err.message}`); + core.setFailed(err.message); throw err; } } diff --git a/src/ContainerRegistryHelper.js b/src/ContainerRegistryHelper.js index 8368631d..c43ce856 100644 --- a/src/ContainerRegistryHelper.js +++ b/src/ContainerRegistryHelper.js @@ -41,6 +41,7 @@ var core = require("@actions/core"); var exec = require("@actions/exec"); var io = require("@actions/io"); var CommandHelper_1 = require("./CommandHelper"); +var Utility_1 = require("./Utility"); var ContainerRegistryHelper = /** @class */ (function () { function ContainerRegistryHelper() { } @@ -119,15 +120,14 @@ var ContainerRegistryHelper = /** @class */ (function () { return [4 /*yield*/, io.which("docker", true)]; case 2: dockerTool = _a.sent(); - return [4 /*yield*/, exec.exec(dockerTool, ["push", "" + imageToPush])]; + return [4 /*yield*/, new Utility_1.Utility().executeAndthrowIfError(dockerTool, ["push", "" + imageToPush])]; case 3: _a.sent(); - core.info("Successfully pushed image \"" + imageToPush + "\" to ACR"); return [3 /*break*/, 5]; case 4: err_3 = _a.sent(); - core.error("Failed to push image \"" + imageToPush + "\" to ACR"); - core.error(err_3.message); + core.error("Failed to push image \"" + imageToPush + "\" to ACR. Error: " + err_3.message); + core.setFailed(err_3.message); throw err_3; case 5: return [2 /*return*/]; } diff --git a/src/ContainerRegistryHelper.ts b/src/ContainerRegistryHelper.ts index 9570b129..367b2dfe 100644 --- a/src/ContainerRegistryHelper.ts +++ b/src/ContainerRegistryHelper.ts @@ -45,18 +45,10 @@ export class ContainerRegistryHelper { core.debug(`Attempting to push image "${imageToPush}" to ACR`); try { const dockerTool: string = await io.which("docker", true); - await exec.exec(dockerTool, [`push`, `${imageToPush}`]) - core.info(`Successfully pushed image "${imageToPush}" to ACR`); - // const dockerTool: string = await io.which("docker", true); - // new Utility().executeAndthrowIfError( - // `${dockerTool}`, - // `push ${imageToPush}`, - // `Failed to push image "${imageToPush}" to ACR` - // ); - + await new Utility().executeAndthrowIfError(dockerTool, [`push`, `${imageToPush}`]); } catch (err) { - core.error(`Failed to push image "${imageToPush}" to ACR`); - core.error(err.message); + core.error(`Failed to push image "${imageToPush}" to ACR. Error: ${err.message}`); + core.setFailed(err.message); throw err; } } diff --git a/src/TelemetryHelper.js b/src/TelemetryHelper.js index 216b9a5e..ca5bec03 100644 --- a/src/TelemetryHelper.js +++ b/src/TelemetryHelper.js @@ -39,7 +39,6 @@ exports.__esModule = true; exports.TelemetryHelper = void 0; var core = require("@actions/core"); var Utility_1 = require("./Utility"); -var exec = require("@actions/exec"); var io = require("@actions/io"); var ORYX_CLI_IMAGE = "mcr.microsoft.com/oryx/cli:debian-buster-20230207.2"; var SUCCESSFUL_RESULT = "succeeded"; @@ -95,7 +94,7 @@ var TelemetryHelper = /** @class */ (function () { case 0: taskLengthMilliseconds = Date.now() - this.taskStartMilliseconds; if (!!this.disableTelemetry) return [3 /*break*/, 4]; - core.debug("Telemetry enabled; logging metadata about task result, length and scenario targeted."); + core.info("Telemetry enabled; logging metadata about task result, length and scenario targeted."); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); @@ -112,13 +111,9 @@ var TelemetryHelper = /** @class */ (function () { errorMessageArg = "--property 'errorMessage=" + this.errorMessage + "'"; } args = ["run", "--rm", "" + ORYX_CLI_IMAGE, "/bin/bash", "-c", "oryx telemetry --event-name 'ContainerAppsPipelinesTaskRCV1' " + ("--processing-time '" + taskLengthMilliseconds + "' " + resultArg + " " + scenarioArg + " " + errorMessageArg + "\"")]; - // const dockerCommand = `run --rm ${ORYX_CLI_IMAGE} /bin/bash -c "oryx telemetry --event-name 'ContainerAppsPipelinesTaskRCV1' ` + - // `--processing-time '${taskLengthMilliseconds}' ${resultArg} ${scenarioArg} ${errorMessageArg}"` // Don't use Utility's throwIfError() since it will still record an error in the pipeline logs, but won't fail the task return [4 /*yield*/, executeDockerCommand(args, true)]; case 2: - // const dockerCommand = `run --rm ${ORYX_CLI_IMAGE} /bin/bash -c "oryx telemetry --event-name 'ContainerAppsPipelinesTaskRCV1' ` + - // `--processing-time '${taskLengthMilliseconds}' ${resultArg} ${scenarioArg} ${errorMessageArg}"` // Don't use Utility's throwIfError() since it will still record an error in the pipeline logs, but won't fail the task _a.sent(); return [3 /*break*/, 4]; @@ -137,39 +132,23 @@ exports.TelemetryHelper = TelemetryHelper; var executeDockerCommand = function (args, continueOnError) { if (continueOnError === void 0) { continueOnError = false; } return __awaiter(void 0, void 0, void 0, function () { - var dockerTool, errorStream, execOptions, exitCode, error_1; + var dockerTool, err_2; return __generator(this, function (_a) { switch (_a.label) { - case 0: return [4 /*yield*/, io.which("docker", true)]; + case 0: + _a.trys.push([0, 3, , 4]); + return [4 /*yield*/, io.which("docker", true)]; case 1: dockerTool = _a.sent(); - errorStream = ''; - execOptions = { - listeners: { - stdout: function (data) { return console.log(data.toString()); } - } - }; - _a.label = 2; + return [4 /*yield*/, new Utility_1.Utility().executeAndthrowIfError(dockerTool, args, continueOnError)]; case 2: - _a.trys.push([2, 4, 5, 6]); - return [4 /*yield*/, exec.exec(dockerTool, args, execOptions)]; + _a.sent(); + return [3 /*break*/, 4]; case 3: - exitCode = _a.sent(); - return [3 /*break*/, 6]; - case 4: - error_1 = _a.sent(); - if (!continueOnError) { - throw error_1; - } - core.warning(error_1); - return [3 /*break*/, 6]; - case 5: - if (exitCode !== 0 && !continueOnError) { - throw new Error(errorStream || 'az cli script failed.'); - } - core.warning(errorStream); - return [7 /*endfinally*/]; - case 6: return [2 /*return*/]; + err_2 = _a.sent(); + core.setFailed("Error: " + err_2.message); + throw err_2; // Re-throw the error + case 4: return [2 /*return*/]; } }); }); diff --git a/src/TelemetryHelper.ts b/src/TelemetryHelper.ts index b4d33443..e9dd9600 100644 --- a/src/TelemetryHelper.ts +++ b/src/TelemetryHelper.ts @@ -1,6 +1,5 @@ import * as core from '@actions/core'; import { Utility } from './Utility'; -import * as exec from '@actions/exec'; import * as io from '@actions/io'; const ORYX_CLI_IMAGE: string = "mcr.microsoft.com/oryx/cli:debian-buster-20230207.2"; @@ -69,7 +68,7 @@ export class TelemetryHelper { public async sendLogs() { const taskLengthMilliseconds: number = Date.now() - this.taskStartMilliseconds; if (!this.disableTelemetry) { - core.debug(`Telemetry enabled; logging metadata about task result, length and scenario targeted.`); + core.info(`Telemetry enabled; logging metadata about task result, length and scenario targeted.`); try { let resultArg: string = ''; if (!util.isNullOrEmpty(this.result)) { @@ -87,8 +86,6 @@ export class TelemetryHelper { } let args: string[] = [`run`, `--rm`, `${ORYX_CLI_IMAGE}`, `/bin/bash`, `-c`, `oryx telemetry --event-name 'ContainerAppsPipelinesTaskRCV1' ` + `--processing-time '${taskLengthMilliseconds}' ${resultArg} ${scenarioArg} ${errorMessageArg}"`]; - // const dockerCommand = `run --rm ${ORYX_CLI_IMAGE} /bin/bash -c "oryx telemetry --event-name 'ContainerAppsPipelinesTaskRCV1' ` + - // `--processing-time '${taskLengthMilliseconds}' ${resultArg} ${scenarioArg} ${errorMessageArg}"` // Don't use Utility's throwIfError() since it will still record an error in the pipeline logs, but won't fail the task await executeDockerCommand(args, true) @@ -100,26 +97,12 @@ export class TelemetryHelper { } const executeDockerCommand = async (args: string[], continueOnError: boolean = false): Promise => { - const dockerTool: string = await io.which("docker", true); - var errorStream: string = ''; - var execOptions: any = { - listeners: { - stdout: (data: any) => console.log(data.toString()), //to log the script output while the script is running. - } - }; - var exitCode; try { - exitCode = await exec.exec(dockerTool, args, execOptions); - } catch (error) { - if (!continueOnError) { - throw error; - } - core.warning(error); + const dockerTool: string = await io.which("docker", true); + await new Utility().executeAndthrowIfError(dockerTool, args, continueOnError); } - finally { - if (exitCode !== 0 && !continueOnError) { - throw new Error(errorStream || 'az cli script failed.'); - } - core.warning(errorStream) + catch (err) { + core.setFailed(`Error: ${err.message}`); + throw err; // Re-throw the error } } \ No newline at end of file diff --git a/src/Utility.js b/src/Utility.js index 91b881d9..87993b49 100644 --- a/src/Utility.js +++ b/src/Utility.js @@ -39,16 +39,18 @@ exports.__esModule = true; exports.Utility = void 0; var core = require("@actions/core"); var exec = require("@actions/exec"); -var util = require('util'); +var util = require("util"); var cpExec = util.promisify(require('child_process').exec); var Utility = /** @class */ (function () { function Utility() { } /** - * @param command - the command to execute - * @param errormsg - the error message to display if the command failed + * @param commandLine - the command to execute + * @param args - the arguments to pass to the command + * @param continueOnError - whether or not to continue execution if the command fails */ - Utility.prototype.executeAndthrowIfError = function (commandToolPath, command, errormsg) { + Utility.prototype.executeAndthrowIfError = function (commandLine, args, continueOnError) { + if (continueOnError === void 0) { continueOnError = false; } return __awaiter(this, void 0, void 0, function () { var stdout_1, stderr_1, options, exitCode, error_1; return __generator(this, function (_a) { @@ -61,21 +63,20 @@ var Utility = /** @class */ (function () { listeners: { stdout: function (data) { stdout_1 += data.toString(); + core.info(data.toString()); }, stderr: function (data) { stderr_1 += data.toString(); + core.error(data.toString()); } } }; - return [4 /*yield*/, exec.exec(commandToolPath, [command], options)]; + return [4 /*yield*/, exec.exec(commandLine, args, options)]; case 1: exitCode = _a.sent(); - if (exitCode !== 0) { - core.error("Command failed with exit code " + exitCode); - if (errormsg) { - core.error("Error Message: " + errormsg); - } - throw new Error("Command failed with exit code " + exitCode); + if (!continueOnError && exitCode !== 0) { + core.error("Command failed with exit code " + exitCode + ". Error stream: " + stderr_1); + throw new Error("Command failed with exit code " + exitCode + ". Error stream: " + stderr_1); } return [3 /*break*/, 3]; case 2: @@ -87,38 +88,27 @@ var Utility = /** @class */ (function () { }); }); }; - Utility.prototype.executeAndReturnExitCode = function (pathToTool, command, errormsg) { + /** + * Sets the Azure CLI to dynamically install extensions that are missing. In this case, we care about the + * Azure Container Apps module being dynamically installed while it's still in preview. + */ + Utility.prototype.setAzureCliDynamicInstall = function () { return __awaiter(this, void 0, void 0, function () { - var stdout_2, stderr_2, options, exitCode, error_2; - return __generator(this, function (_a) { - switch (_a.label) { + var _a, stdout, stderr, error_2; + return __generator(this, function (_b) { + switch (_b.label) { case 0: - _a.trys.push([0, 2, , 3]); - stdout_2 = ''; - stderr_2 = ''; - options = { - listeners: { - stdout: function (data) { - stdout_2 += data.toString(); - }, - stderr: function (data) { - stderr_2 += data.toString(); - } - } - }; - return [4 /*yield*/, exec.exec(pathToTool, [command], options)]; + _b.trys.push([0, 2, , 3]); + return [4 /*yield*/, cpExec("az config set extension.use_dynamic_install=yes_without_prompt")]; case 1: - exitCode = _a.sent(); - if (exitCode !== 0) { - core.error("Command failed with exit code " + exitCode); - if (errormsg) { - core.error("Error Message: " + errormsg); - } - throw new Error("Command failed with exit code " + exitCode); + _a = _b.sent(), stdout = _a.stdout, stderr = _a.stderr; + if (stderr) { + core.error("Unable to set Azure CLI to dynamically install extensions. Error: " + stderr); + throw new Error("Unable to set Azure CLI to dynamically install extensions. Error: " + stderr); } - return [2 /*return*/, exitCode]; + return [3 /*break*/, 3]; case 2: - error_2 = _a.sent(); + error_2 = _b.sent(); core.setFailed("Error: " + error_2.message); throw error_2; // Re-throw the error case 3: return [2 /*return*/]; @@ -126,61 +116,6 @@ var Utility = /** @class */ (function () { }); }); }; - Utility.prototype.executeAndReturnOutput = function (pathToTool, command, errormsg) { - return __awaiter(this, void 0, void 0, function () { - var stdout_3, stderr_3, options, exitCode, error_3; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 2, , 3]); - stdout_3 = ''; - stderr_3 = ''; - options = { - listeners: { - stdout: function (data) { - stdout_3 += data.toString(); - }, - stderr: function (data) { - stderr_3 += data.toString(); - } - } - }; - return [4 /*yield*/, exec.exec(pathToTool, [command], options)]; - case 1: - exitCode = _a.sent(); - if (exitCode !== 0) { - core.error("Command failed with exit code " + exitCode); - if (errormsg) { - core.error("Error Message: " + errormsg); - } - throw new Error("Command failed with exit code " + exitCode); - } - return [2 /*return*/, stdout_3]; - case 2: - error_3 = _a.sent(); - core.setFailed("Error: " + error_3.message); - throw error_3; // Re-throw the error - case 3: return [2 /*return*/]; - } - }); - }); - }; - /** - * Sets the Azure CLI to dynamically install extensions that are missing. In this case, we care about the - * Azure Container Apps module being dynamically installed while it's still in preview. - */ - Utility.prototype.setAzureCliDynamicInstall = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, cpExec("az config set extension.use_dynamic_install=yes_without_prompt")]; - case 1: - _a.sent(); - return [2 /*return*/]; - } - }); - }); - }; /** * Checks whether or not the provided string is null, undefined or empty. * @param str - the string to validate diff --git a/src/Utility.ts b/src/Utility.ts index 7da1d8c6..51f5f107 100644 --- a/src/Utility.ts +++ b/src/Utility.ts @@ -1,128 +1,68 @@ import * as core from '@actions/core'; import * as exec from '@actions/exec'; -import { cp } from 'fs'; -const util = require('util'); +import util = require('util'); const cpExec = util.promisify(require('child_process').exec); export class Utility { - /** - * @param command - the command to execute - * @param errormsg - the error message to display if the command failed - */ + /** + * @param commandLine - the command to execute + * @param args - the arguments to pass to the command + * @param continueOnError - whether or not to continue execution if the command fails + */ - public async executeAndthrowIfError(commandToolPath: string, command: string, errormsg?: string): Promise { - try { - let stdout = ''; - let stderr = ''; + public async executeAndthrowIfError(commandLine: string, args: string[], continueOnError: boolean = false): Promise { + try { + let stdout = ''; + let stderr = ''; - const options: exec.ExecOptions = { - listeners: { - stdout: (data: Buffer) => { - stdout += data.toString(); - }, - stderr: (data: Buffer) => { - stderr += data.toString(); - }, - }, - }; + const options: exec.ExecOptions = { + listeners: { + stdout: (data: Buffer) => { + stdout += data.toString(); + core.info(data.toString()); + }, + stderr: (data: Buffer) => { + stderr += data.toString(); + core.error(data.toString()); + }, + }, + }; - const exitCode = await exec.exec(commandToolPath, [command], options); + const exitCode = await exec.exec(commandLine, args, options); - if (exitCode!== 0) { - core.error(`Command failed with exit code ${exitCode}`); - if (errormsg) { - core.error(`Error Message: ${errormsg}`); - } - throw new Error(`Command failed with exit code ${exitCode}`); - } - } catch (error) { - core.setFailed(`Error: ${error.message}`); - throw error; // Re-throw the error - } + if (!continueOnError && exitCode !== 0) { + core.error(`Command failed with exit code ${exitCode}. Error stream: ${stderr}`); + throw new Error(`Command failed with exit code ${exitCode}. Error stream: ${stderr}`); + } + } catch (error) { + core.setFailed(`Error: ${error.message}`); + throw error; // Re-throw the error } + } - public async executeAndReturnExitCode(pathToTool: string, command: string, errormsg?: string): Promise { - try { - let stdout = ''; - let stderr = ''; - - const options: exec.ExecOptions = { - listeners: { - stdout: (data: Buffer) => { - stdout += data.toString(); - }, - stderr: (data: Buffer) => { - stderr += data.toString(); - }, - }, - }; - - const exitCode = await exec.exec(pathToTool, [command], options); - - if (exitCode!== 0) { - core.error(`Command failed with exit code ${exitCode}`); - if (errormsg) { - core.error(`Error Message: ${errormsg}`); - } - throw new Error(`Command failed with exit code ${exitCode}`); - } - return exitCode; - } catch (error) { - core.setFailed(`Error: ${error.message}`); - throw error; // Re-throw the error - } + /** + * Sets the Azure CLI to dynamically install extensions that are missing. In this case, we care about the + * Azure Container Apps module being dynamically installed while it's still in preview. + */ + public async setAzureCliDynamicInstall() { + try { + const { stdout, stderr } = await cpExec(`az config set extension.use_dynamic_install=yes_without_prompt`); + if (stderr) { + core.error(`Unable to set Azure CLI to dynamically install extensions. Error: ${stderr}`); + throw new Error(`Unable to set Azure CLI to dynamically install extensions. Error: ${stderr}`); + } } - - public async executeAndReturnOutput(pathToTool: string, command: string, errormsg?: string): Promise { - try { - let stdout = ''; - let stderr = ''; - - const options: exec.ExecOptions = { - listeners: { - stdout: (data: Buffer) => { - stdout += data.toString(); - }, - stderr: (data: Buffer) => { - stderr += data.toString(); - }, - }, - }; - - const exitCode = await exec.exec(pathToTool, [command], options); - - if (exitCode!== 0) { - core.error(`Command failed with exit code ${exitCode}`); - if (errormsg) { - core.error(`Error Message: ${errormsg}`); - } - throw new Error(`Command failed with exit code ${exitCode}`); - } - return stdout; - } catch (error) { - core.setFailed(`Error: ${error.message}`); - throw error; // Re-throw the error - } + catch (error) { + core.setFailed(`Error: ${error.message}`); + throw error; // Re-throw the error } + } - - /** - * Sets the Azure CLI to dynamically install extensions that are missing. In this case, we care about the - * Azure Container Apps module being dynamically installed while it's still in preview. - */ - public async setAzureCliDynamicInstall() { - await cpExec(`az config set extension.use_dynamic_install=yes_without_prompt`); - // this.executeAndthrowIfError( - // `az config set extension.use_dynamic_install=yes_without_prompt`, - // `Unable to set Azure CLI to dynamically install extensions.` - // ); - } - - /** - * Checks whether or not the provided string is null, undefined or empty. - * @param str - the string to validate - * @returns true if the string is null, undefined or empty, false otherwise - */ - public isNullOrEmpty(str: string): boolean { - return str === null || str === undefined || str === ""; - } + /** + * Checks whether or not the provided string is null, undefined or empty. + * @param str - the string to validate + * @returns true if the string is null, undefined or empty, false otherwise + */ + public isNullOrEmpty(str: string): boolean { + return str === null || str === undefined || str === ""; + } } \ No newline at end of file