diff --git a/.github/workflows/run-validation.yml b/.github/workflows/run-validation.yml index 32e12d60..f2de473b 100644 --- a/.github/workflows/run-validation.yml +++ b/.github/workflows/run-validation.yml @@ -19,6 +19,7 @@ env: jobs: create-using-builder: + name: 'Create app using builder' runs-on: ubuntu-latest timeout-minutes: 10 @@ -60,6 +61,12 @@ jobs: shell: bash run: az containerapp delete -n ${{ env.TEST_CONTAINER_APP_NAME }} -g ${{ vars.TEST_RESOURCE_GROUP_NAME }} -y + - name: Delete pushed image + if: ${{ always() }} + shell: bash + run: az acr repository delete -n ${{ vars.TEST_ACR_NAME }} -t ${{ env.TEST_IMAGE_REPOSITORY }}:${{ env.TEST_IMAGE_TAG }} -y + + create-using-builder-and-internal-registry: name: 'Create app using builder and push to internal registry' @@ -141,6 +148,11 @@ jobs: shell: bash run: az containerapp delete -n ${{ env.TEST_CONTAINER_APP_NAME }} -g ${{ vars.TEST_RESOURCE_GROUP_NAME }} -y + - name: Delete pushed image + if: ${{ always() }} + shell: bash + run: az acr repository delete -n ${{ vars.TEST_ACR_NAME }} -t ${{ env.TEST_IMAGE_REPOSITORY }}:${{ env.TEST_IMAGE_TAG }} -y + create-using-provided-dockerfile: name: 'Create app using provided Dockerfile' @@ -190,6 +202,7 @@ jobs: shell: bash run: az acr repository delete -n ${{ vars.TEST_ACR_NAME }} -t ${{ env.TEST_IMAGE_REPOSITORY }}:${{ env.TEST_IMAGE_TAG }} -y + create-using-image-linux: name: 'Create app using image on Linux runner' diff --git a/README.md b/README.md index 8f721a95..162a2b5a 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ For more information on the structure of the YAML configuration file, please vis | `resourceGroup` | No | The existing resource group that the Azure Container App will be created in. If not provided, this value will be `-rg` and its existence will first be checked before attempting to create it. | | `containerAppEnvironment` | No | The name of the Container App environment to use with the application. If not provided, an existing environment in the resource group of the Container App will be used, otherwise, an environment will be created in the formation `-env`. | | `runtimeStack` | No | The platform version stack used in the final runnable application image that is deployed to the Container App. The value should be provided in the formation `:`. If not provided, this value is determined by Oryx based on the contents of the provided application. Please refer to [this document](https://github.com/microsoft/Oryx/blob/main/doc/supportedRuntimeVersions.md) for more information on supported runtime stacks for Oryx. | -| `builderStack` | No | The stack (OS) that should be used to build the provided application source and produce the runnable application image. You can provide a specific image tag for the stack, such as "debian-bookworm-20231004.1", or you can provide a supported stack name, such as "debian-bookworm" or "debian-bullseye", and the latest supported image tag for that stack will be used. If no stack is provided, this action will attempt to build the provided application source with each supported stack until there's a successful build. | +| `builderStack` | No | The stack (OS) that should be used to build the provided application source and produce the runnable application image. You can provide a specific image tag for the stack, such as "debian-bookworm-20231107.2", or you can provide a supported stack name, such as "debian-bookworm" or "debian-bullseye", and the latest supported image tag for that stack will be used. If no stack is provided, this action will attempt to build the provided application source with each supported stack until there's a successful build. | | `targetPort` | No | The designated port for the application to run on. If no value is provided and the builder is used to build the runnable application image, the target port will be set to 80 for Python applications and 8080 for all other platform applications. If no value is provided when creating a Container App, the target port will default to 80. Note: when using this action to update a Container App, the target port may be updated if not provided based on changes to the ingress property. | | `location` | No | The location that the Container App (and other created resources) will be deployed to. To view locations suitable for creating the Container App in, please run the following: `az provider show -n Microsoft.App --query "resourceTypes[?resourceType=='containerApps'].locations"` | | `environmentVariables` | No | A list of environment variable(s) for the container. Space-separated values in 'key=value' format. Empty string to clear existing values. Prefix value with 'secretref:' to reference a secret. | diff --git a/action.yml b/action.yml index 384bff60..743c5c03 100644 --- a/action.yml +++ b/action.yml @@ -83,7 +83,7 @@ inputs: builderStack: description: | 'The stack (OS) that should be used to build the provided application source and produce the runnable application - image. You can provide a specific image tag for the stack, such as "debian-bullseye-20231004.1", or you can + image. You can provide a specific image tag for the stack, such as "debian-bullseye-20231107.2", or you can provide a supported stack name, such as "debian-bookworm" or "debian-bullseye", and the latest supported image tag for that stack will be used. If no stack is provided, this action will attempt to build the provided application source with each supported stack until there's a successful build.' diff --git a/azurecontainerapps.ts b/azurecontainerapps.ts index bf41421c..c4f05db9 100644 --- a/azurecontainerapps.ts +++ b/azurecontainerapps.ts @@ -31,13 +31,18 @@ export class azurecontainerapps { await this.authenticateAzureContainerRegistryAsync(); } + // Set up property to determine if the internal registry should be used + this.useInternalRegistry = this.util.isNullOrEmpty(this.registryUrl); // Set up property to determine if the internal registry should be used this.useInternalRegistry = this.util.isNullOrEmpty(this.registryUrl); + // Set up property to trigger cloud build with 'up' command + this.shouldCreateOrUpdateContainerAppWithUp = !this.util.isNullOrEmpty(this.appSourcePath) && this.useInternalRegistry; // Set up property to trigger cloud build with 'up' command this.shouldCreateOrUpdateContainerAppWithUp = !this.util.isNullOrEmpty(this.appSourcePath) && this.useInternalRegistry; // If the application source was provided, build a runnable application image from it + if (!this.useInternalRegistry && !this.util.isNullOrEmpty(this.appSourcePath)) { if (!this.useInternalRegistry && !this.util.isNullOrEmpty(this.appSourcePath)) { await this.buildAndPushImageAsync(); } @@ -180,8 +185,8 @@ export class azurecontainerapps { * setting the Azure CLI to install missing extensions. */ private static async setupAzureCli() { - // Set the Azure CLI to install missing extension - await this.util.installAzureCliExtension(); + // Set the Azure CLI to install missing extensions + // await this.util.installAzureCliExtension(); } /** @@ -233,6 +238,12 @@ export class azurecontainerapps { // Set deployment location, if provided let location: string = this.toolHelper.getInput('location', false); + let doesContainerAppExist = await this.appHelper.doesContainerAppExist(this.containerAppName, this.resourceGroup); + if (doesContainerAppExist) { + var environmentId = await this.appHelper.getExistingContainerAppEnvironmentId(this.containerAppName); + var environmentName = environmentId.split("/").pop(); + location = await this.appHelper.getExistingContainerAppEnvironmentLocation(environmentName); + } // If no location was provided, use the default location for the Container App service if (this.util.isNullOrEmpty(location)) { location = await this.appHelper.getDefaultContainerAppLocation(); @@ -304,6 +315,9 @@ export class azurecontainerapps { await this.appHelper.createContainerAppEnvironment(containerAppEnvironment, resourceGroup, location); } + // Set default location to the location of the Container App environment + this.location = await this.appHelper.getExistingContainerAppEnvironmentLocation(containerAppEnvironment); + return containerAppEnvironment; } @@ -346,25 +360,26 @@ export class azurecontainerapps { // If telemetry is enabled, log that the previously built image scenario was targeted for this task this.telemetryHelper.setImageScenario(); } + /** * Builds a runnable application image using a Dockerfile or the builder and pushes it to the Container Registry. */ private static async buildAndPushImageAsync() { - // Get the name of the image to build if it was provided, or generate it from build variables - this.imageToBuild = this.toolHelper.getInput('imageToBuild', false); - - if (this.util.isNullOrEmpty(this.imageToBuild)) { - const imageRepository = this.toolHelper.getDefaultImageRepository() - // Constructs the image to build based on the provided registry URL, image repository, build ID, and build number. - this.imageToBuild = `${this.registryUrl}/${imageRepository}:${this.buildId}.${this.buildNumber}`; - this.toolHelper.writeInfo(`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 (this.util.isNullOrEmpty(this.imageToDeploy)) { - this.imageToDeploy = this.imageToBuild; - this.toolHelper.writeInfo(`Default image to deploy: ${this.imageToDeploy}`); - } + // Get the name of the image to build if it was provided, or generate it from build variables + this.imageToBuild = this.toolHelper.getInput('imageToBuild', false); + + if (this.util.isNullOrEmpty(this.imageToBuild)) { + const imageRepository = this.toolHelper.getDefaultImageRepository() + // Constructs the image to build based on the provided registry URL, image repository, build ID, and build number. + this.imageToBuild = `${this.registryUrl}/${imageRepository}:${this.buildId}.${this.buildNumber}`; + this.toolHelper.writeInfo(`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 (this.util.isNullOrEmpty(this.imageToDeploy)) { + this.imageToDeploy = this.imageToBuild; + this.toolHelper.writeInfo(`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 = this.toolHelper.getInput('dockerfilePath', false); @@ -546,7 +561,7 @@ export class azurecontainerapps { // Create the Container App from the YAML configuration file await this.appHelper.createContainerAppFromYaml(this.containerAppName, this.resourceGroup, this.yamlConfigPath); } else if (this.shouldCreateOrUpdateContainerAppWithUp) { - await this.appHelper.createOrUpdateContainerAppWithUp(this.containerAppName, this.resourceGroup, this.commandLineArgs); + await this.appHelper.createOrUpdateContainerAppWithUp(this.containerAppName, this.resourceGroup, this.commandLineArgs, this.location); } else { // Create the Container App from command line arguments await this.appHelper.createContainerApp(this.containerAppName, this.resourceGroup, this.containerAppEnvironment, this.commandLineArgs); diff --git a/dist/index.js b/dist/index.js index f2801267..de8e4b64 100644 --- a/dist/index.js +++ b/dist/index.js @@ -119,7 +119,7 @@ var azurecontainerapps = /** @class */ (function () { this.toolHelper.setFailed(err_1.message); this.telemetryHelper.setFailedResult(err_1.message); return [3 /*break*/, 14]; - case 12: + case 12: // If telemetry is enabled, will log metadata for this task run return [4 /*yield*/, this.telemetryHelper.sendLogs()]; case 13: @@ -190,11 +190,11 @@ var azurecontainerapps = /** @class */ (function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { - case 0: - // Set the Azure CLI to install missing extension - return [4 /*yield*/, this.util.installAzureCliExtension()]; + case 0: + // Set the Azure CLI to dynamically install missing extensions + return [4 /*yield*/, this.util.setAzureCliDynamicInstall()]; case 1: - // Set the Azure CLI to install missing extension + // Set the Azure CLI to dynamically install missing extensions _a.sent(); return [2 /*return*/]; } @@ -264,17 +264,30 @@ var azurecontainerapps = /** @class */ (function () { */ azurecontainerapps.getLocation = function () { return __awaiter(this, void 0, void 0, function () { - var location; + var location, doesContainerAppExist, environmentId, environmentName; return __generator(this, function (_a) { switch (_a.label) { case 0: location = this.toolHelper.getInput('location', false); - if (!this.util.isNullOrEmpty(location)) return [3 /*break*/, 2]; - return [4 /*yield*/, this.appHelper.getDefaultContainerAppLocation()]; + return [4 /*yield*/, this.appHelper.doesContainerAppExist(this.containerAppName, this.resourceGroup)]; case 1: + doesContainerAppExist = _a.sent(); + if (!doesContainerAppExist) return [3 /*break*/, 4]; + return [4 /*yield*/, this.appHelper.getExistingContainerAppEnvironmentId(this.containerAppName)]; + case 2: + environmentId = _a.sent(); + environmentName = environmentId.split("/").pop(); + return [4 /*yield*/, this.appHelper.getExistingContainerAppEnvironmentLocation(environmentName)]; + case 3: location = _a.sent(); - _a.label = 2; - case 2: return [2 /*return*/, location]; + _a.label = 4; + case 4: + if (!this.util.isNullOrEmpty(location)) return [3 /*break*/, 6]; + return [4 /*yield*/, this.appHelper.getDefaultContainerAppLocation()]; + case 5: + location = _a.sent(); + _a.label = 6; + case 6: return [2 /*return*/, location]; } }); }); @@ -322,20 +335,20 @@ var azurecontainerapps = /** @class */ (function () { */ azurecontainerapps.getOrCreateContainerAppEnvironment = function (containerAppName, resourceGroup, location) { return __awaiter(this, void 0, void 0, function () { - var containerAppEnvironment, existingContainerAppEnvironment, containerAppEnvironmentExists; - return __generator(this, function (_a) { - switch (_a.label) { + var containerAppEnvironment, existingContainerAppEnvironment, containerAppEnvironmentExists, _a; + return __generator(this, function (_b) { + switch (_b.label) { case 0: containerAppEnvironment = this.toolHelper.getInput('containerAppEnvironment', false); if (!this.util.isNullOrEmpty(containerAppEnvironment)) return [3 /*break*/, 2]; return [4 /*yield*/, this.appHelper.getExistingContainerAppEnvironment(resourceGroup)]; case 1: - existingContainerAppEnvironment = _a.sent(); + existingContainerAppEnvironment = _b.sent(); if (!this.util.isNullOrEmpty(existingContainerAppEnvironment)) { this.toolHelper.writeInfo("Existing Container App environment found in resource group: " + existingContainerAppEnvironment); return [2 /*return*/, existingContainerAppEnvironment]; } - _a.label = 2; + _b.label = 2; case 2: // Generate the Container App environment name if it was not provided if (this.util.isNullOrEmpty(containerAppEnvironment)) { @@ -344,13 +357,20 @@ var azurecontainerapps = /** @class */ (function () { } return [4 /*yield*/, this.appHelper.doesContainerAppEnvironmentExist(containerAppEnvironment, resourceGroup)]; case 3: - containerAppEnvironmentExists = _a.sent(); + containerAppEnvironmentExists = _b.sent(); if (!!containerAppEnvironmentExists) return [3 /*break*/, 5]; return [4 /*yield*/, this.appHelper.createContainerAppEnvironment(containerAppEnvironment, resourceGroup, location)]; case 4: - _a.sent(); - _a.label = 5; - case 5: return [2 /*return*/, containerAppEnvironment]; + _b.sent(); + _b.label = 5; + case 5: + // Set default location to the location of the Container App environment + _a = this; + return [4 /*yield*/, this.appHelper.getExistingContainerAppEnvironmentLocation(containerAppEnvironment)]; + case 6: + // Set default location to the location of the Container App environment + _a.location = _b.sent(); + return [2 /*return*/, containerAppEnvironment]; } }); }); @@ -441,7 +461,7 @@ var azurecontainerapps = /** @class */ (function () { this.toolHelper.writeInfo("Dockerfile found at root of application source."); dockerfilePath = rootDockerfilePath; return [3 /*break*/, 3]; - case 1: + case 1: // No Dockerfile found or provided, build the image using the builder return [4 /*yield*/, this.buildImageFromBuilderAsync(this.appSourcePath, this.imageToBuild)]; case 2: @@ -460,7 +480,7 @@ var azurecontainerapps = /** @class */ (function () { // Build the image from the provided/discovered Dockerfile _a.sent(); _a.label = 7; - case 7: + case 7: // Push the image to the Container Registry return [4 /*yield*/, this.registryHelper.pushImageToContainerRegistry(this.imageToBuild)]; case 8: @@ -481,7 +501,7 @@ var azurecontainerapps = /** @class */ (function () { var environmentVariables, runtimeStack, runtimeStackSplit, platformName, platformVersion, builderStack; return __generator(this, function (_a) { switch (_a.label) { - case 0: + case 0: // Install the pack CLI return [4 /*yield*/, this.appHelper.installPackCliAsync()]; case 1: @@ -633,11 +653,11 @@ var azurecontainerapps = /** @class */ (function () { return [3 /*break*/, 6]; case 2: if (!this.shouldCreateOrUpdateContainerAppWithUp) return [3 /*break*/, 4]; - return [4 /*yield*/, this.appHelper.createOrUpdateContainerAppWithUp(this.containerAppName, this.resourceGroup, this.commandLineArgs)]; + return [4 /*yield*/, this.appHelper.createOrUpdateContainerAppWithUp(this.containerAppName, this.resourceGroup, this.commandLineArgs, this.location)]; case 3: _a.sent(); return [3 /*break*/, 6]; - case 4: + case 4: // Create the Container App from command line arguments return [4 /*yield*/, this.appHelper.createContainerApp(this.containerAppName, this.resourceGroup, this.containerAppEnvironment, this.commandLineArgs)]; case 5: @@ -660,7 +680,7 @@ var azurecontainerapps = /** @class */ (function () { case 10: _a.sent(); _a.label = 11; - case 11: + case 11: // Update the Container App using the 'update' command return [4 /*yield*/, this.appHelper.updateContainerApp(this.containerAppName, this.resourceGroup, this.commandLineArgs)]; case 12: @@ -673,7 +693,7 @@ var azurecontainerapps = /** @class */ (function () { case 14: _a.sent(); return [3 /*break*/, 17]; - case 15: + case 15: // Update the Container App using the 'up' command return [4 /*yield*/, this.appHelper.updateContainerAppWithUp(this.containerAppName, this.resourceGroup, this.commandLineArgs, this.ingress, this.targetPort)]; case 16: @@ -1254,8 +1274,8 @@ class OidcClient { const res = yield httpclient .getJson(id_token_url) .catch(error => { - throw new Error(`Failed to get ID Token. \n - Error Code : ${error.statusCode}\n + throw new Error(`Failed to get ID Token. \n + Error Code : ${error.statusCode}\n Error Message: ${error.message}`); }); const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value; @@ -4700,8 +4720,8 @@ var Utility_1 = __nccwpck_require__(2135); var GitHubActionsToolHelper_1 = __nccwpck_require__(3185); var fs = __nccwpck_require__(7147); var ORYX_CLI_IMAGE = 'mcr.microsoft.com/oryx/cli:builder-debian-bullseye-20230926.1'; -var ORYX_BULLSEYE_BUILDER_IMAGE = 'mcr.microsoft.com/oryx/builder:debian-bullseye-20231025.1'; -var ORYX_BOOKWORM_BUILDER_IMAGE = 'mcr.microsoft.com/oryx/builder:debian-bookworm-20231025.1'; +var ORYX_BULLSEYE_BUILDER_IMAGE = 'mcr.microsoft.com/oryx/builder:debian-bullseye-20231107.2'; +var ORYX_BOOKWORM_BUILDER_IMAGE = 'mcr.microsoft.com/oryx/builder:debian-bookworm-20231107.2'; var ORYX_BUILDER_IMAGES = [ORYX_BULLSEYE_BUILDER_IMAGE, ORYX_BOOKWORM_BUILDER_IMAGE]; var IS_WINDOWS_AGENT = os.platform() == 'win32'; var PACK_CMD = IS_WINDOWS_AGENT ? path.join(os.tmpdir(), 'pack') : 'pack'; @@ -4752,7 +4772,7 @@ var ContainerAppHelper = /** @class */ (function () { * @param resourceGroup - the resource group that the Container App is found in * @param optionalCmdArgs - a set of optional command line arguments */ - ContainerAppHelper.prototype.createOrUpdateContainerAppWithUp = function (containerAppName, resourceGroup, optionalCmdArgs) { + ContainerAppHelper.prototype.createOrUpdateContainerAppWithUp = function (containerAppName, resourceGroup, optionalCmdArgs, location) { return __awaiter(this, void 0, void 0, function () { var command_2, err_2; return __generator(this, function (_a) { @@ -4762,7 +4782,7 @@ var ContainerAppHelper = /** @class */ (function () { _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); - command_2 = "az containerapp up -n " + containerAppName + " -g " + resourceGroup + " -l northcentralusstage"; + command_2 = "az containerapp up -n " + containerAppName + " -g " + resourceGroup + " -l " + location + " --debug"; optionalCmdArgs.forEach(function (val) { command_2 += " " + val; }); @@ -5090,6 +5110,54 @@ var ContainerAppHelper = /** @class */ (function () { }); }); }; + /** + * Gets the location of an existing Container App Environment + */ + ContainerAppHelper.prototype.getExistingContainerAppEnvironmentLocation = function (environmentName) { + return __awaiter(this, void 0, void 0, function () { + var command, executionResult, err_13; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + _a.trys.push([0, 2, , 3]); + command = "az containerapp env show -n " + environmentName + " --query \"[0].location\""; + return [4 /*yield*/, util.execute(command)]; + case 1: + executionResult = _a.sent(); + return [2 /*return*/, executionResult.exitCode === 0 ? executionResult.stdout : null]; + case 2: + err_13 = _a.sent(); + toolHelper.writeInfo(err_13.message); + return [2 /*return*/, null]; + case 3: return [2 /*return*/]; + } + }); + }); + }; + /** + * Gets the environment Id of an existing Container App + */ + ContainerAppHelper.prototype.getExistingContainerAppEnvironmentId = function (containerAppName) { + return __awaiter(this, void 0, void 0, function () { + var command, executionResult, err_14; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + _a.trys.push([0, 2, , 3]); + command = "az containerapp show -n " + containerAppName + " --query \"[0].properties.environmentId\""; + return [4 /*yield*/, util.execute(command)]; + case 1: + executionResult = _a.sent(); + return [2 /*return*/, executionResult.exitCode === 0 ? executionResult.stdout : null]; + case 2: + err_14 = _a.sent(); + toolHelper.writeInfo(err_14.message); + return [2 /*return*/, null]; + case 3: return [2 /*return*/]; + } + }); + }); + }; /** * Creates a new Azure Container App Environment in the provided resource group. * @param name - the name of the Container App Environment @@ -5098,7 +5166,7 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.createContainerAppEnvironment = function (name, resourceGroup, location) { return __awaiter(this, void 0, void 0, function () { - var util, command, err_13; + var util, command, err_15; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -5116,9 +5184,9 @@ var ContainerAppHelper = /** @class */ (function () { _a.sent(); return [3 /*break*/, 4]; case 3: - err_13 = _a.sent(); - toolHelper.writeError(err_13.message); - throw err_13; + err_15 = _a.sent(); + toolHelper.writeError(err_15.message); + throw err_15; case 4: return [2 /*return*/]; } }); @@ -5131,7 +5199,7 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.disableContainerAppIngress = function (name, resourceGroup) { return __awaiter(this, void 0, void 0, function () { - var command, err_14; + var command, err_16; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -5145,9 +5213,9 @@ var ContainerAppHelper = /** @class */ (function () { _a.sent(); return [3 /*break*/, 4]; case 3: - err_14 = _a.sent(); - toolHelper.writeError(err_14.message); - throw err_14; + err_16 = _a.sent(); + toolHelper.writeError(err_16.message); + throw err_16; case 4: return [2 /*return*/]; } }); @@ -5163,7 +5231,7 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.updateContainerAppRegistryDetails = function (name, resourceGroup, registryUrl, registryUsername, registryPassword) { return __awaiter(this, void 0, void 0, function () { - var command, err_15; + var command, err_17; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -5177,9 +5245,9 @@ var ContainerAppHelper = /** @class */ (function () { _a.sent(); return [3 /*break*/, 4]; case 3: - err_15 = _a.sent(); - toolHelper.writeError(err_15.message); - throw err_15; + err_17 = _a.sent(); + toolHelper.writeError(err_17.message); + throw err_17; case 4: return [2 /*return*/]; } }); @@ -5204,7 +5272,7 @@ var ContainerAppHelper = /** @class */ (function () { } couldBuildImage = false; _loop_1 = function (builderImage) { - var command_5, err_16; + var command_5, err_18; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -5225,8 +5293,8 @@ var ContainerAppHelper = /** @class */ (function () { couldBuildImage = true; return [2 /*return*/, "break"]; case 3: - err_16 = _a.sent(); - toolHelper.writeWarning("Unable to run 'pack build' command to produce runnable application image: " + err_16.message); + err_18 = _a.sent(); + toolHelper.writeWarning("Unable to run 'pack build' command to produce runnable application image: " + err_18.message); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } @@ -5268,7 +5336,7 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.createRunnableAppImageFromDockerfile = function (imageToDeploy, appSourcePath, dockerfilePath) { return __awaiter(this, void 0, void 0, function () { - var command, err_17; + var command, err_19; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -5283,9 +5351,9 @@ var ContainerAppHelper = /** @class */ (function () { toolHelper.writeDebug("Successfully created runnable application image from the provided/found Dockerfile \"" + dockerfilePath + "\" with image name \"" + imageToDeploy + "\""); return [3 /*break*/, 4]; case 3: - err_17 = _a.sent(); - toolHelper.writeError(err_17.message); - throw err_17; + err_19 = _a.sent(); + toolHelper.writeError(err_19.message); + throw err_19; case 4: return [2 /*return*/]; } }); @@ -5298,7 +5366,7 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.determineRuntimeStackAsync = function (appSourcePath) { return __awaiter(this, void 0, void 0, function () { - var command, oryxRuntimeTxtPath_1, runtimeStack, err_18; + var command, oryxRuntimeTxtPath_1, runtimeStack, err_20; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -5328,9 +5396,9 @@ var ContainerAppHelper = /** @class */ (function () { }); return [2 /*return*/, runtimeStack]; case 3: - err_18 = _a.sent(); - toolHelper.writeError(err_18.message); - throw err_18; + err_20 = _a.sent(); + toolHelper.writeError(err_20.message); + throw err_20; case 4: return [2 /*return*/]; } }); @@ -5342,7 +5410,7 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.setDefaultBuilder = function () { return __awaiter(this, void 0, void 0, function () { - var command, err_19; + var command, err_21; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -5356,9 +5424,9 @@ var ContainerAppHelper = /** @class */ (function () { _a.sent(); return [3 /*break*/, 4]; case 3: - err_19 = _a.sent(); - toolHelper.writeError(err_19.message); - throw err_19; + err_21 = _a.sent(); + toolHelper.writeError(err_21.message); + throw err_21; case 4: return [2 /*return*/]; } }); @@ -5370,7 +5438,7 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.installPackCliAsync = function () { return __awaiter(this, void 0, void 0, function () { - var command, commandLine, packZipDownloadUri, packZipDownloadFilePath, tgzSuffix, err_20; + var command, commandLine, packZipDownloadUri, packZipDownloadFilePath, tgzSuffix, err_22; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -5397,9 +5465,9 @@ var ContainerAppHelper = /** @class */ (function () { _a.sent(); return [3 /*break*/, 4]; case 3: - err_20 = _a.sent(); - toolHelper.writeError("Unable to install the pack CLI. Error: " + err_20.message); - throw err_20; + err_22 = _a.sent(); + toolHelper.writeError("Unable to install the pack CLI. Error: " + err_22.message); + throw err_22; case 4: return [2 /*return*/]; } }); @@ -5410,7 +5478,7 @@ var ContainerAppHelper = /** @class */ (function () { */ ContainerAppHelper.prototype.enablePackCliExperimentalFeaturesAsync = function () { return __awaiter(this, void 0, void 0, function () { - var command, err_21; + var command, err_23; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -5424,9 +5492,9 @@ var ContainerAppHelper = /** @class */ (function () { _a.sent(); return [3 /*break*/, 4]; case 3: - err_21 = _a.sent(); - toolHelper.writeError("Unable to enable experimental features for the pack CLI: " + err_21.message); - throw err_21; + err_23 = _a.sent(); + toolHelper.writeError("Unable to enable experimental features for the pack CLI: " + err_23.message); + throw err_23; case 4: return [2 /*return*/]; } }); @@ -6070,7 +6138,7 @@ module.exports = require("util"); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; -/******/ +/******/ /******/ // The require function /******/ function __nccwpck_require__(moduleId) { /******/ // Check if module is in cache @@ -6084,7 +6152,7 @@ module.exports = require("util"); /******/ // no module.loaded needed /******/ exports: {} /******/ }; -/******/ +/******/ /******/ // Execute the module function /******/ var threw = true; /******/ try { @@ -6093,23 +6161,23 @@ module.exports = require("util"); /******/ } finally { /******/ if(threw) delete __webpack_module_cache__[moduleId]; /******/ } -/******/ +/******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } -/******/ +/******/ /************************************************************************/ /******/ /* webpack/runtime/compat */ -/******/ +/******/ /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/"; -/******/ +/******/ /************************************************************************/ -/******/ +/******/ /******/ // startup /******/ // Load entry module and return exports /******/ // This entry module is referenced by other modules so it can't be inlined /******/ var __webpack_exports__ = __nccwpck_require__(3238); /******/ module.exports = __webpack_exports__; -/******/ +/******/ /******/ })() ; \ No newline at end of file diff --git a/src/ContainerAppHelper.ts b/src/ContainerAppHelper.ts index 75ae3bbe..a80e8b37 100644 --- a/src/ContainerAppHelper.ts +++ b/src/ContainerAppHelper.ts @@ -5,8 +5,8 @@ import { GitHubActionsToolHelper } from './GitHubActionsToolHelper' import fs = require('fs'); const ORYX_CLI_IMAGE: string = 'mcr.microsoft.com/oryx/cli:builder-debian-bullseye-20230926.1'; -const ORYX_BULLSEYE_BUILDER_IMAGE: string = 'mcr.microsoft.com/oryx/builder:debian-bullseye-20231025.1' -const ORYX_BOOKWORM_BUILDER_IMAGE: string = 'mcr.microsoft.com/oryx/builder:debian-bookworm-20231025.1' +const ORYX_BULLSEYE_BUILDER_IMAGE: string = 'mcr.microsoft.com/oryx/builder:debian-bullseye-20231107.2' +const ORYX_BOOKWORM_BUILDER_IMAGE: string = 'mcr.microsoft.com/oryx/builder:debian-bookworm-20231107.2' const ORYX_BUILDER_IMAGES: string[] = [ ORYX_BULLSEYE_BUILDER_IMAGE, ORYX_BOOKWORM_BUILDER_IMAGE ]; const IS_WINDOWS_AGENT: boolean = os.platform() == 'win32'; const PACK_CMD: string = IS_WINDOWS_AGENT ? path.join(os.tmpdir(), 'pack') : 'pack'; @@ -54,10 +54,11 @@ export class ContainerAppHelper { public async createOrUpdateContainerAppWithUp( containerAppName: string, resourceGroup: string, - optionalCmdArgs: string[]) { + optionalCmdArgs: string[], + location: string) { toolHelper.writeDebug(`Attempting to create Container App with name "${containerAppName}" in resource group "${resourceGroup}"`); try { - let command = `az containerapp up -n ${containerAppName} -g ${resourceGroup} -l northcentralusstage`; + let command = `az containerapp up -n ${containerAppName} -g ${resourceGroup} -l ${location} --debug`; optionalCmdArgs.forEach(function (val: string) { command += ` ${val}`; }); @@ -271,6 +272,34 @@ export class ContainerAppHelper { } } + /** + * Gets the location of an existing Container App Environment + */ + public async getExistingContainerAppEnvironmentLocation(environmentName: string) { + try { + let command = `az containerapp env show -n ${environmentName} --query "[0].location"` + let executionResult = await util.execute(command); + return executionResult.exitCode === 0 ? executionResult.stdout : null; + } catch (err) { + toolHelper.writeInfo(err.message); + return null; + } + } + + /** + * Gets the environment Id of an existing Container App + */ + public async getExistingContainerAppEnvironmentId(containerAppName: string) { + try { + let command = `az containerapp show -n ${containerAppName} --query "[0].properties.environmentId"` + let executionResult = await util.execute(command); + return executionResult.exitCode === 0 ? executionResult.stdout : null; + } catch (err) { + toolHelper.writeInfo(err.message); + return null; + } + } + /** * Creates a new Azure Container App Environment in the provided resource group. * @param name - the name of the Container App Environment