From 2672857762f05e6456a9e821e5301089644e5b81 Mon Sep 17 00:00:00 2001 From: Luke Phillips-Sheard Date: Tue, 8 Oct 2024 16:44:40 +0100 Subject: [PATCH 1/3] Support ARN being passed in as well as a file --- README.md | 45 ++++++++++++++++++++++++++++++-------------- dist/index.js | 52 +++++++++++++++++++++++++++++++++------------------ index.js | 51 +++++++++++++++++++++++++++++++++----------------- index.test.js | 14 ++++++++++++++ 4 files changed, 113 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 3d9f2fd40..f7df36ec9 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ Registers an Amazon ECS task definition and deploys it to an ECS service. - [Usage](#usage) - + [Task definition file](#task-definition-file) - + [Task definition container image values](#task-definition-container-image-values) + - [Task definition file](#task-definition-file) + - [Task definition container image values](#task-definition-container-image-values) - [Credentials and Region](#credentials-and-region) - [Permissions](#permissions) - [AWS CodeDeploy Support](#aws-codedeploy-support) @@ -31,14 +31,15 @@ Registers an Amazon ECS task definition and deploys it to an ECS service. ``` See [action.yml](action.yml) for the full documentation for this action's inputs and outputs. -In most cases when running a one-off task, subnet ID's, subnet groups, and assign public IP will be required. -Assign public IP will only be applied when a subnet or security group is defined. +In most cases when running a one-off task, subnet ID's, subnet groups, and assign public IP will be required. +Assign public IP will only be applied when a subnet or security group is defined. ### Task definition file It is highly recommended to treat the task definition "as code" by checking it into your git repository as a JSON file. Changes to any task definition attributes like container images, environment variables, CPU, and memory can be deployed with this GitHub action by editing your task definition file and pushing a new git commit. An existing task definition can be downloaded to a JSON file with the following command. Account IDs can be removed from the file by removing the `taskDefinitionArn` attribute, and updating the `executionRoleArn` and `taskRoleArn` attribute values to contain role names instead of role ARNs. + ```sh aws ecs describe-task-definition \ --task-definition my-task-definition-family \ @@ -46,12 +47,14 @@ aws ecs describe-task-definition \ ``` Alternatively, you can start a new task definition file from scratch with the following command. In the generated file, fill in your attribute values and remove any attributes not needed for your application. + ```sh aws ecs register-task-definition \ --generate-cli-skeleton > task-definition.json ``` If you do not wish to store your task definition as a file in your git repository, your GitHub Actions workflow can download the existing task definition. + ```yaml - name: Download task definition run: | @@ -104,6 +107,18 @@ The task definition file can be updated prior to deployment with the new contain wait-for-service-stability: true ``` +If you're using CloudFormation tools such as AWS CDK, Serverless Framework, or others to construct your task definition, you can directly pass the ARN of the task definition. For example: + +```yaml + - name: Deploy Amazon ECS task definition + uses: aws-actions/amazon-ecs-deploy-task-definition@v1 + with: + task-definition: arn:aws:ecs:::task-definition/: + service: my-service + cluster: my-cluster + wait-for-service-stability: true +``` + ### Tags To turn on [Amazon ECS-managed tags](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-using-tags.html#managed-tags) `aws:ecs:serviceName` and `aws:ecs:clusterName` for the tasks in the service or the standalone tasks by setting `enable-ecs-managed-tags`: @@ -138,15 +153,16 @@ This action relies on the [default behavior of the AWS SDK for Javascript](https Use [the `aws-actions/configure-aws-credentials` action](https://github.com/aws-actions/configure-aws-credentials) to configure the GitHub Actions environment with environment variables containing AWS credentials and your desired region. We recommend following [Amazon IAM best practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) for the AWS credentials used in GitHub Actions workflows, including: -* Do not store credentials in your repository's code. You may use [GitHub Actions secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets) to store credentials and redact credentials from GitHub Actions workflow logs. -* [Create an individual IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users) with an access key for use in GitHub Actions workflows, preferably one per repository. Do not use the AWS account root user access key. -* [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) to the credentials used in GitHub Actions workflows. Grant only the permissions required to perform the actions in your GitHub Actions workflows. See the Permissions section below for the permissions required by this action. -* [Rotate the credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#rotate-credentials) used in GitHub Actions workflows regularly. -* [Monitor the activity](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#keep-a-log) of the credentials used in GitHub Actions workflows. +- Do not store credentials in your repository's code. You may use [GitHub Actions secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets) to store credentials and redact credentials from GitHub Actions workflow logs. +- [Create an individual IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users) with an access key for use in GitHub Actions workflows, preferably one per repository. Do not use the AWS account root user access key. +- [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) to the credentials used in GitHub Actions workflows. Grant only the permissions required to perform the actions in your GitHub Actions workflows. See the Permissions section below for the permissions required by this action. +- [Rotate the credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#rotate-credentials) used in GitHub Actions workflows regularly. +- [Monitor the activity](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#keep-a-log) of the credentials used in GitHub Actions workflows. ## Permissions Running a service requires the following minimum set of permissions: + ```json { "Version":"2012-10-17", @@ -184,8 +200,9 @@ Running a service requires the following minimum set of permissions: ] } ``` - + Running a one-off/stand-alone task requires the following minimum set of permissions: + ```json { "Version": "2012-10-17", @@ -214,6 +231,7 @@ Running a one-off/stand-alone task requires the following minimum set of permiss ] } ``` + Note: the policy above assumes the account has opted in to the ECS long ARN format. ## AWS CodeDeploy Support @@ -298,15 +316,15 @@ In the following example, the service would not be updated until the ad-hoc task wait-for-task-stopped: true ``` -Overrides and VPC networking options are available as well. See [action.yml](action.yml) for more details. The `FARGATE` +Overrides and VPC networking options are available as well. See [action.yml](action.yml) for more details. The `FARGATE` launch type requires `awsvpc` network mode in your task definition and you must specify a network configuration. ### Tags To tag your tasks: -* to turn on Amazon ECS-managed tags (`aws:ecs:clusterName`), use `enable-ecs-managed-tags` -* for custom tags, use `run-task-tags` +- to turn on Amazon ECS-managed tags (`aws:ecs:clusterName`), use `enable-ecs-managed-tags` +- for custom tags, use `run-task-tags` ```yaml - name: Deploy to Amazon ECS @@ -333,4 +351,3 @@ This code is made available under the MIT license. ## Security Disclosures If you would like to report a potential security issue in this project, please do not create a GitHub issue. Instead, please follow the instructions [here](https://aws.amazon.com/security/vulnerability-reporting/) or [email AWS security directly](mailto:aws-security@amazon.com). - diff --git a/dist/index.js b/dist/index.js index 6c9c79dbd..9e179dc71 100644 --- a/dist/index.js +++ b/dist/index.js @@ -391,7 +391,7 @@ async function run() { }); // Get inputs - const taskDefinitionFile = core.getInput('task-definition', { required: true }); + const taskDefinitionInput = core.getInput('task-definition', { required: true }); const service = core.getInput('service', { required: false }); const cluster = core.getInput('cluster', { required: false }); const waitForService = core.getInput('wait-for-service-stability', { required: false }); @@ -411,23 +411,39 @@ async function run() { } const propagateTags = core.getInput('propagate-tags', { required: false }) || 'NONE'; - // Register the task definition - core.debug('Registering the task definition'); - const taskDefPath = path.isAbsolute(taskDefinitionFile) ? - taskDefinitionFile : - path.join(process.env.GITHUB_WORKSPACE, taskDefinitionFile); - const fileContents = fs.readFileSync(taskDefPath, 'utf8'); - const taskDefContents = maintainValidObjects(removeIgnoredAttributes(cleanNullKeys(yaml.parse(fileContents)))); - let registerResponse; - try { - registerResponse = await ecs.registerTaskDefinition(taskDefContents); - } catch (error) { - core.setFailed("Failed to register task definition in ECS: " + error.message); - core.debug("Task definition contents:"); - core.debug(JSON.stringify(taskDefContents, undefined, 4)); - throw(error); + let taskDefArn = null; + + // Of taskDefContent starts with arn: then we assume it is a task definition ARN + if (taskDefinitionContent.startsWith("arn:")) { + taskDefArn = taskDefinitionContent; + + // + // Else we assume it is a task definition file + } else { + const taskDefinitionFile = taskDefinitionContent; + + core.debug('Registering the task definition'); + const taskDefPath = path.isAbsolute(taskDefinitionFile) ? + taskDefinitionFile : + path.join(process.env.GITHUB_WORKSPACE, taskDefinitionFile); + const fileContents = fs.readFileSync(taskDefPath, 'utf8'); + const taskDefContents = maintainValidObjects(removeIgnoredAttributes(cleanNullKeys(yaml.parse(fileContents)))); + try { + const registerResponse = await ecs.registerTaskDefinition(taskDefContents); + taskDefArn = registerResponse.taskDefinition.taskDefinitionArn; + } catch (error) { + core.setFailed("Failed to register task definition in ECS: " + error.message); + core.debug("Task definition contents:"); + core.debug(JSON.stringify(taskDefContents, undefined, 4)); + throw(error); + } + } + + if (!taskDefArn) { + core.setFailed('Task definition ARN is not defined'); + throw new Error('Task definition ARN is not defined'); } - const taskDefArn = registerResponse.taskDefinition.taskDefinitionArn; + core.setOutput('task-definition-arn', taskDefArn); // Run the task outside of the service @@ -486,7 +502,7 @@ module.exports = run; if (require.main === require.cache[eval('__filename')]) { run(); } - +// /***/ }), diff --git a/index.js b/index.js index b24760e2b..567f1ee86 100644 --- a/index.js +++ b/index.js @@ -385,7 +385,7 @@ async function run() { }); // Get inputs - const taskDefinitionFile = core.getInput('task-definition', { required: true }); + const taskDefinitionInput = core.getInput('task-definition', { required: true }); const service = core.getInput('service', { required: false }); const cluster = core.getInput('cluster', { required: false }); const waitForService = core.getInput('wait-for-service-stability', { required: false }); @@ -405,23 +405,39 @@ async function run() { } const propagateTags = core.getInput('propagate-tags', { required: false }) || 'NONE'; - // Register the task definition - core.debug('Registering the task definition'); - const taskDefPath = path.isAbsolute(taskDefinitionFile) ? - taskDefinitionFile : - path.join(process.env.GITHUB_WORKSPACE, taskDefinitionFile); - const fileContents = fs.readFileSync(taskDefPath, 'utf8'); - const taskDefContents = maintainValidObjects(removeIgnoredAttributes(cleanNullKeys(yaml.parse(fileContents)))); - let registerResponse; - try { - registerResponse = await ecs.registerTaskDefinition(taskDefContents); - } catch (error) { - core.setFailed("Failed to register task definition in ECS: " + error.message); - core.debug("Task definition contents:"); - core.debug(JSON.stringify(taskDefContents, undefined, 4)); - throw(error); + let taskDefArn = null; + + // Of taskDefContent starts with arn: then we assume it is a task definition ARN + if (taskDefinitionContent.startsWith("arn:")) { + taskDefArn = taskDefinitionContent; + + // + // Else we assume it is a task definition file + } else { + const taskDefinitionFile = taskDefinitionContent; + + core.debug('Registering the task definition'); + const taskDefPath = path.isAbsolute(taskDefinitionFile) ? + taskDefinitionFile : + path.join(process.env.GITHUB_WORKSPACE, taskDefinitionFile); + const fileContents = fs.readFileSync(taskDefPath, 'utf8'); + const taskDefContents = maintainValidObjects(removeIgnoredAttributes(cleanNullKeys(yaml.parse(fileContents)))); + try { + const registerResponse = await ecs.registerTaskDefinition(taskDefContents); + taskDefArn = registerResponse.taskDefinition.taskDefinitionArn; + } catch (error) { + core.setFailed("Failed to register task definition in ECS: " + error.message); + core.debug("Task definition contents:"); + core.debug(JSON.stringify(taskDefContents, undefined, 4)); + throw(error); + } + } + + if (!taskDefArn) { + core.setFailed('Task definition ARN is not defined'); + throw new Error('Task definition ARN is not defined'); } - const taskDefArn = registerResponse.taskDefinition.taskDefinitionArn; + core.setOutput('task-definition-arn', taskDefArn); // Run the task outside of the service @@ -480,3 +496,4 @@ module.exports = run; if (require.main === module) { run(); } +// \ No newline at end of file diff --git a/index.test.js b/index.test.js index 493c520cc..325e31f12 100644 --- a/index.test.js +++ b/index.test.js @@ -172,6 +172,20 @@ describe('Deploy to ECS', () => { waitUntilDeploymentSuccessful.mockImplementation(() => Promise.resolve({})); }); + test('uses task definition ARN if taskDefinitionContent starts with arn:', async () => { + core.getInput = jest + .fn() + .mockReturnValueOnce('arn:aws:ecs:region:account-id:task-definition/task-name:task-revision') // task-definition + .mockReturnValueOnce('service-456') // service + .mockReturnValueOnce('cluster-789'); // cluster + + await run(); + + expect(core.setFailed).toHaveBeenCalledTimes(0); + expect(mockEcsRegisterTaskDef).toHaveBeenCalledTimes(0); // Importante, não deve chamar a função de registro + expect(core.setOutput).toHaveBeenNthCalledWith(1, 'task-definition-arn', 'arn:aws:ecs:region:account-id:task-definition/task-name:task-revision'); + }); + test('registers the task definition contents and updates the service', async () => { await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); From 50b4dc2dde27b50befbcec2a33e7d8af8d481f76 Mon Sep 17 00:00:00 2001 From: Luke Phillips-Sheard Date: Tue, 8 Oct 2024 17:34:57 +0100 Subject: [PATCH 2/3] fix variable name --- dist/index.js | 2 +- index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/index.js b/dist/index.js index 9e179dc71..9311a4644 100644 --- a/dist/index.js +++ b/dist/index.js @@ -391,7 +391,7 @@ async function run() { }); // Get inputs - const taskDefinitionInput = core.getInput('task-definition', { required: true }); + const taskDefinitionContent = core.getInput('task-definition', { required: true }); const service = core.getInput('service', { required: false }); const cluster = core.getInput('cluster', { required: false }); const waitForService = core.getInput('wait-for-service-stability', { required: false }); diff --git a/index.js b/index.js index 567f1ee86..744290dc3 100644 --- a/index.js +++ b/index.js @@ -385,7 +385,7 @@ async function run() { }); // Get inputs - const taskDefinitionInput = core.getInput('task-definition', { required: true }); + const taskDefinitionContent = core.getInput('task-definition', { required: true }); const service = core.getInput('service', { required: false }); const cluster = core.getInput('cluster', { required: false }); const waitForService = core.getInput('wait-for-service-stability', { required: false }); From 8fb28c1ca5b23ea0f2caba6da7b4bad447e870c4 Mon Sep 17 00:00:00 2001 From: Rahul Parsani Date: Tue, 9 Dec 2025 00:25:55 +0530 Subject: [PATCH 3/3] seperate arn --- README.md | 37 ++-- action.yml | 7 +- dist/index.js | 25 +-- index.js | 24 +-- index.test.js | 556 +++++++++++++++++++++++++------------------------- 5 files changed, 328 insertions(+), 321 deletions(-) diff --git a/README.md b/README.md index f7df36ec9..01d9c7a06 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ Registers an Amazon ECS task definition and deploys it to an ECS service. - [Usage](#usage) - - [Task definition file](#task-definition-file) - - [Task definition container image values](#task-definition-container-image-values) + + [Task definition file](#task-definition-file) + + [Task definition container image values](#task-definition-container-image-values) - [Credentials and Region](#credentials-and-region) - [Permissions](#permissions) - [AWS CodeDeploy Support](#aws-codedeploy-support) @@ -31,15 +31,14 @@ Registers an Amazon ECS task definition and deploys it to an ECS service. ``` See [action.yml](action.yml) for the full documentation for this action's inputs and outputs. -In most cases when running a one-off task, subnet ID's, subnet groups, and assign public IP will be required. -Assign public IP will only be applied when a subnet or security group is defined. +In most cases when running a one-off task, subnet ID's, subnet groups, and assign public IP will be required. +Assign public IP will only be applied when a subnet or security group is defined. ### Task definition file It is highly recommended to treat the task definition "as code" by checking it into your git repository as a JSON file. Changes to any task definition attributes like container images, environment variables, CPU, and memory can be deployed with this GitHub action by editing your task definition file and pushing a new git commit. An existing task definition can be downloaded to a JSON file with the following command. Account IDs can be removed from the file by removing the `taskDefinitionArn` attribute, and updating the `executionRoleArn` and `taskRoleArn` attribute values to contain role names instead of role ARNs. - ```sh aws ecs describe-task-definition \ --task-definition my-task-definition-family \ @@ -47,14 +46,12 @@ aws ecs describe-task-definition \ ``` Alternatively, you can start a new task definition file from scratch with the following command. In the generated file, fill in your attribute values and remove any attributes not needed for your application. - ```sh aws ecs register-task-definition \ --generate-cli-skeleton > task-definition.json ``` If you do not wish to store your task definition as a file in your git repository, your GitHub Actions workflow can download the existing task definition. - ```yaml - name: Download task definition run: | @@ -111,9 +108,9 @@ If you're using CloudFormation tools such as AWS CDK, Serverless Framework, or o ```yaml - name: Deploy Amazon ECS task definition - uses: aws-actions/amazon-ecs-deploy-task-definition@v1 + uses: aws-actions/amazon-ecs-deploy-task-definition@v2 with: - task-definition: arn:aws:ecs:::task-definition/: + task-definition-arn: arn:aws:ecs:::task-definition/: service: my-service cluster: my-cluster wait-for-service-stability: true @@ -153,16 +150,15 @@ This action relies on the [default behavior of the AWS SDK for Javascript](https Use [the `aws-actions/configure-aws-credentials` action](https://github.com/aws-actions/configure-aws-credentials) to configure the GitHub Actions environment with environment variables containing AWS credentials and your desired region. We recommend following [Amazon IAM best practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) for the AWS credentials used in GitHub Actions workflows, including: -- Do not store credentials in your repository's code. You may use [GitHub Actions secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets) to store credentials and redact credentials from GitHub Actions workflow logs. -- [Create an individual IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users) with an access key for use in GitHub Actions workflows, preferably one per repository. Do not use the AWS account root user access key. -- [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) to the credentials used in GitHub Actions workflows. Grant only the permissions required to perform the actions in your GitHub Actions workflows. See the Permissions section below for the permissions required by this action. -- [Rotate the credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#rotate-credentials) used in GitHub Actions workflows regularly. -- [Monitor the activity](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#keep-a-log) of the credentials used in GitHub Actions workflows. +* Do not store credentials in your repository's code. You may use [GitHub Actions secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets) to store credentials and redact credentials from GitHub Actions workflow logs. +* [Create an individual IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users) with an access key for use in GitHub Actions workflows, preferably one per repository. Do not use the AWS account root user access key. +* [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) to the credentials used in GitHub Actions workflows. Grant only the permissions required to perform the actions in your GitHub Actions workflows. See the Permissions section below for the permissions required by this action. +* [Rotate the credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#rotate-credentials) used in GitHub Actions workflows regularly. +* [Monitor the activity](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#keep-a-log) of the credentials used in GitHub Actions workflows. ## Permissions Running a service requires the following minimum set of permissions: - ```json { "Version":"2012-10-17", @@ -200,9 +196,8 @@ Running a service requires the following minimum set of permissions: ] } ``` - + Running a one-off/stand-alone task requires the following minimum set of permissions: - ```json { "Version": "2012-10-17", @@ -231,7 +226,6 @@ Running a one-off/stand-alone task requires the following minimum set of permiss ] } ``` - Note: the policy above assumes the account has opted in to the ECS long ARN format. ## AWS CodeDeploy Support @@ -316,15 +310,15 @@ In the following example, the service would not be updated until the ad-hoc task wait-for-task-stopped: true ``` -Overrides and VPC networking options are available as well. See [action.yml](action.yml) for more details. The `FARGATE` +Overrides and VPC networking options are available as well. See [action.yml](action.yml) for more details. The `FARGATE` launch type requires `awsvpc` network mode in your task definition and you must specify a network configuration. ### Tags To tag your tasks: -- to turn on Amazon ECS-managed tags (`aws:ecs:clusterName`), use `enable-ecs-managed-tags` -- for custom tags, use `run-task-tags` +* to turn on Amazon ECS-managed tags (`aws:ecs:clusterName`), use `enable-ecs-managed-tags` +* for custom tags, use `run-task-tags` ```yaml - name: Deploy to Amazon ECS @@ -351,3 +345,4 @@ This code is made available under the MIT license. ## Security Disclosures If you would like to report a potential security issue in this project, please do not create a GitHub issue. Instead, please follow the instructions [here](https://aws.amazon.com/security/vulnerability-reporting/) or [email AWS security directly](mailto:aws-security@amazon.com). + diff --git a/action.yml b/action.yml index 08b3098c7..65d2185b6 100644 --- a/action.yml +++ b/action.yml @@ -5,8 +5,11 @@ branding: color: 'orange' inputs: task-definition: - description: 'The path to the ECS task definition file to register.' - required: true + description: 'The path to the ECS task definition file to register. Either this or task-definition-arn must be provided.' + required: false + task-definition-arn: + description: 'The ARN of an existing ECS task definition to deploy. Either this or task-definition must be provided.' + required: false desired-count: description: 'The number of instantiations of the task to place and keep running in your service.' required: false diff --git a/dist/index.js b/dist/index.js index 9311a4644..63f4200c4 100644 --- a/dist/index.js +++ b/dist/index.js @@ -391,7 +391,8 @@ async function run() { }); // Get inputs - const taskDefinitionContent = core.getInput('task-definition', { required: true }); + const taskDefinitionArn = core.getInput('task-definition-arn', { required: false }); + const taskDefinitionFile = core.getInput('task-definition', { required: false }); const service = core.getInput('service', { required: false }); const cluster = core.getInput('cluster', { required: false }); const waitForService = core.getInput('wait-for-service-stability', { required: false }); @@ -413,18 +414,14 @@ async function run() { let taskDefArn = null; - // Of taskDefContent starts with arn: then we assume it is a task definition ARN - if (taskDefinitionContent.startsWith("arn:")) { - taskDefArn = taskDefinitionContent; - - // - // Else we assume it is a task definition file - } else { - const taskDefinitionFile = taskDefinitionContent; - + // Prioritize task-definition-arn if provided + if (taskDefinitionArn) { + taskDefArn = taskDefinitionArn; + } else if (taskDefinitionFile) { + // Fall back to task-definition file if provided core.debug('Registering the task definition'); const taskDefPath = path.isAbsolute(taskDefinitionFile) ? - taskDefinitionFile : + taskDefinitionFile : path.join(process.env.GITHUB_WORKSPACE, taskDefinitionFile); const fileContents = fs.readFileSync(taskDefPath, 'utf8'); const taskDefContents = maintainValidObjects(removeIgnoredAttributes(cleanNullKeys(yaml.parse(fileContents)))); @@ -437,6 +434,10 @@ async function run() { core.debug(JSON.stringify(taskDefContents, undefined, 4)); throw(error); } + } else { + // Error if neither is provided + core.setFailed('Either task-definition or task-definition-arn must be provided'); + throw new Error('Either task-definition or task-definition-arn must be provided'); } if (!taskDefArn) { @@ -502,7 +503,7 @@ module.exports = run; if (require.main === require.cache[eval('__filename')]) { run(); } -// + /***/ }), diff --git a/index.js b/index.js index 744290dc3..50f24bb5f 100644 --- a/index.js +++ b/index.js @@ -385,7 +385,8 @@ async function run() { }); // Get inputs - const taskDefinitionContent = core.getInput('task-definition', { required: true }); + const taskDefinitionArn = core.getInput('task-definition-arn', { required: false }); + const taskDefinitionFile = core.getInput('task-definition', { required: false }); const service = core.getInput('service', { required: false }); const cluster = core.getInput('cluster', { required: false }); const waitForService = core.getInput('wait-for-service-stability', { required: false }); @@ -407,18 +408,14 @@ async function run() { let taskDefArn = null; - // Of taskDefContent starts with arn: then we assume it is a task definition ARN - if (taskDefinitionContent.startsWith("arn:")) { - taskDefArn = taskDefinitionContent; - - // - // Else we assume it is a task definition file - } else { - const taskDefinitionFile = taskDefinitionContent; - + // Prioritize task-definition-arn if provided + if (taskDefinitionArn) { + taskDefArn = taskDefinitionArn; + } else if (taskDefinitionFile) { + // Fall back to task-definition file if provided core.debug('Registering the task definition'); const taskDefPath = path.isAbsolute(taskDefinitionFile) ? - taskDefinitionFile : + taskDefinitionFile : path.join(process.env.GITHUB_WORKSPACE, taskDefinitionFile); const fileContents = fs.readFileSync(taskDefPath, 'utf8'); const taskDefContents = maintainValidObjects(removeIgnoredAttributes(cleanNullKeys(yaml.parse(fileContents)))); @@ -431,6 +428,10 @@ async function run() { core.debug(JSON.stringify(taskDefContents, undefined, 4)); throw(error); } + } else { + // Error if neither is provided + core.setFailed('Either task-definition or task-definition-arn must be provided'); + throw new Error('Either task-definition or task-definition-arn must be provided'); } if (!taskDefArn) { @@ -496,4 +497,3 @@ module.exports = run; if (require.main === module) { run(); } -// \ No newline at end of file diff --git a/index.test.js b/index.test.js index 325e31f12..23715dce4 100644 --- a/index.test.js +++ b/index.test.js @@ -54,11 +54,14 @@ describe('Deploy to ECS', () => { beforeEach(() => { jest.clearAllMocks(); - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789'); // cluster + core.getInput = jest.fn(input => { + const defaults = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'cluster-789' + }; + return defaults[input] || ''; + }); process.env = Object.assign(process.env, { GITHUB_WORKSPACE: __dirname }); @@ -172,20 +175,41 @@ describe('Deploy to ECS', () => { waitUntilDeploymentSuccessful.mockImplementation(() => Promise.resolve({})); }); - test('uses task definition ARN if taskDefinitionContent starts with arn:', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('arn:aws:ecs:region:account-id:task-definition/task-name:task-revision') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789'); // cluster + test('uses task definition ARN if task-definition-arn is provided', async () => { + core.getInput = jest.fn(input => { + const values = { + 'task-definition-arn': 'arn:aws:ecs:region:account-id:task-definition/task-name:task-revision', + 'task-definition': '', + 'service': 'service-456', + 'cluster': 'cluster-789' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); - expect(mockEcsRegisterTaskDef).toHaveBeenCalledTimes(0); // Importante, não deve chamar a função de registro + expect(mockEcsRegisterTaskDef).toHaveBeenCalledTimes(0); // Should not call register function expect(core.setOutput).toHaveBeenNthCalledWith(1, 'task-definition-arn', 'arn:aws:ecs:region:account-id:task-definition/task-name:task-revision'); }); + test('errors if neither task-definition nor task-definition-arn is provided', async () => { + core.getInput = jest.fn(input => { + const values = { + 'task-definition-arn': '', + 'task-definition': '', + 'service': 'service-456', + 'cluster': 'cluster-789' + }; + return values[input] || ''; + }); + + await run(); + + expect(core.setFailed).toHaveBeenCalledWith('Either task-definition or task-definition-arn must be provided'); + expect(mockEcsRegisterTaskDef).toHaveBeenCalledTimes(0); + }); + test('registers the task definition contents and updates the service', async () => { await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -494,12 +518,15 @@ describe('Deploy to ECS', () => { }); test('registers the task definition contents and creates a CodeDeploy deployment, waits for 30 minutes + deployment group wait time', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789') // cluster - .mockReturnValueOnce('TRUE'); // wait-for-service-stability + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'cluster-789', + 'wait-for-service-stability': 'TRUE' + }; + return values[input] || ''; + }); mockEcsDescribeServices.mockImplementation( () => Promise.resolve({ @@ -571,13 +598,16 @@ describe('Deploy to ECS', () => { }); test('registers the task definition contents and creates a CodeDeploy deployment, waits for 1 hour + deployment group\'s wait time', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789') // cluster - .mockReturnValueOnce('TRUE') // wait-for-service-stability - .mockReturnValueOnce('60'); // wait-for-minutes + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'cluster-789', + 'wait-for-service-stability': 'TRUE', + 'wait-for-minutes': '60' + }; + return values[input] || ''; + }); mockEcsDescribeServices.mockImplementation( () => Promise.resolve({ @@ -647,13 +677,16 @@ describe('Deploy to ECS', () => { }); test('registers the task definition contents and creates a CodeDeploy deployment, waits for max 6 hours', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789') // cluster - .mockReturnValueOnce('TRUE') // wait-for-service-stability - .mockReturnValueOnce('1000'); // wait-for-minutes + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'cluster-789', + 'wait-for-service-stability': 'TRUE', + 'wait-for-minutes': '1000' + }; + return values[input] || ''; + }); mockEcsDescribeServices.mockImplementation( () => Promise.resolve({ @@ -719,21 +752,18 @@ describe('Deploy to ECS', () => { }); test('does not wait for a CodeDeploy deployment, parses JSON appspec file', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789') // cluster - .mockReturnValueOnce('false') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // run-task - .mockReturnValueOnce('') // desired count - .mockReturnValueOnce('') // enable-ecs-managed-tags - .mockReturnValueOnce('') // propagate-task - .mockReturnValueOnce('/hello/appspec.json') // codedeploy-appspec - .mockReturnValueOnce('MyApplication') // codedeploy-application - .mockReturnValueOnce('MyDeploymentGroup'); // codedeploy-deployment-group + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'cluster-789', + 'wait-for-service-stability': 'false', + 'codedeploy-appspec': '/hello/appspec.json', + 'codedeploy-application': 'MyApplication', + 'codedeploy-deployment-group': 'MyDeploymentGroup' + }; + return values[input] || ''; + }); fs.readFileSync.mockReturnValue(` { @@ -925,7 +955,12 @@ describe('Deploy to ECS', () => { }); test('registers the task definition contents at an absolute path', async () => { - core.getInput = jest.fn().mockReturnValueOnce('/hello/task-definition.json'); + core.getInput = jest.fn(input => { + const values = { + 'task-definition': '/hello/task-definition.json' + }; + return values[input] || ''; + }); fs.readFileSync.mockImplementation((pathInput, encoding) => { if (encoding != 'utf8') { throw new Error(`Wrong encoding ${encoding}`); @@ -946,13 +981,15 @@ describe('Deploy to ECS', () => { }); test('waits for the service to be stable', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789') // cluster - .mockReturnValueOnce('TRUE') // wait-for-service-stability - .mockReturnValueOnce(''); // desired count + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'cluster-789', + 'wait-for-service-stability': 'TRUE' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -986,14 +1023,16 @@ describe('Deploy to ECS', () => { }); test('waits for the service to be stable for specified minutes', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789') // cluster - .mockReturnValueOnce('TRUE') // wait-for-service-stability - .mockReturnValueOnce('60') // wait-for-minutes - .mockReturnValueOnce(''); // desired count + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'cluster-789', + 'wait-for-service-stability': 'TRUE', + 'wait-for-minutes': '60' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1027,14 +1066,17 @@ describe('Deploy to ECS', () => { }); test('waits for the service to be stable for max 6 hours', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789') // cluster - .mockReturnValueOnce('TRUE') // wait-for-service-stability - .mockReturnValueOnce('1000') // wait-for-minutes - .mockReturnValueOnce('abc'); // desired count is NaN + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'cluster-789', + 'wait-for-service-stability': 'TRUE', + 'wait-for-minutes': '1000', + 'desired-count': 'abc' // NaN test + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1068,15 +1110,17 @@ describe('Deploy to ECS', () => { }); test('force new deployment', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789') // cluster - .mockReturnValueOnce('false') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('true') // force-new-deployment - .mockReturnValueOnce('4'); // desired count is number + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'cluster-789', + 'wait-for-service-stability': 'false', + 'force-new-deployment': 'true', + 'desired-count': '4' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1099,11 +1143,13 @@ describe('Deploy to ECS', () => { }); test('defaults to the default cluster', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce(''); // desired count + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1125,9 +1171,12 @@ describe('Deploy to ECS', () => { }); test('does not update service if none specified', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json'); // task-definition + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1139,18 +1188,13 @@ describe('Deploy to ECS', () => { }); test('run task', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('') // service - .mockReturnValueOnce('') // cluster - .mockReturnValueOnce('') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // enable-ecs-managed-tags - .mockReturnValueOnce('') // propagate-tags - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('true'); // run-task + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'run-task': 'true' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1174,26 +1218,22 @@ describe('Deploy to ECS', () => { }); test('run task with options', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('') // service - .mockReturnValueOnce('somecluster') // cluster - .mockReturnValueOnce('') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('false') // enable-ecs-managed-tags - .mockReturnValueOnce('') // propagate-tags - .mockReturnValueOnce('true') // run-task - .mockReturnValueOnce('false') // wait-for-task-stopped - .mockReturnValueOnce('someJoe') // run-task-started-by - .mockReturnValueOnce('EC2') // run-task-launch-type - .mockReturnValueOnce('a,b') // run-task-subnet-ids - .mockReturnValueOnce('c,d') // run-task-security-group-ids - .mockReturnValueOnce(JSON.stringify([{ name: 'someapp', command: 'somecmd' }])) // run-task-container-overrides - .mockReturnValueOnce('') // run-task-assign-public-IP - .mockReturnValueOnce('[{"key": "project", "value": "myproject"}]'); // run-task-tags + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'cluster': 'somecluster', + 'enable-ecs-managed-tags': 'false', + 'run-task': 'true', + 'wait-for-task-stopped': 'false', + 'run-task-started-by': 'someJoe', + 'run-task-launch-type': 'EC2', + 'run-task-subnets': 'a,b', + 'run-task-security-groups': 'c,d', + 'run-task-container-overrides': JSON.stringify([{ name: 'someapp', command: 'somecmd' }]), + 'run-task-tags': '[{"key": "project", "value": "myproject"}]' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1215,27 +1255,22 @@ describe('Deploy to ECS', () => { }); test('run task with capacity provider strategy', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('') // service - .mockReturnValueOnce('somecluster') // cluster - .mockReturnValueOnce('') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('false') // enable-ecs-managed-tags - .mockReturnValueOnce('') // propagate-tags - .mockReturnValueOnce('true') // run-task - .mockReturnValueOnce('false') // wait-for-task-stopped - .mockReturnValueOnce('someJoe') // run-task-started-by - .mockReturnValueOnce('') // run-task-launch-type - .mockReturnValueOnce('a,b') // run-task-subnet-ids - .mockReturnValueOnce('c,d') // run-task-security-group-ids - .mockReturnValueOnce(JSON.stringify([{ name: 'someapp', command: 'somecmd' }])) // run-task-container-overrides - .mockReturnValueOnce('') // run-task-assign-public-IP - .mockReturnValueOnce('[{"key": "project", "value": "myproject"}]') // run-task-tags - .mockReturnValueOnce('[{"capacityProvider":"FARGATE_SPOT","weight":1}]'); // run-task-capacity-provider-strategy + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'cluster': 'somecluster', + 'enable-ecs-managed-tags': 'false', + 'run-task': 'true', + 'wait-for-task-stopped': 'false', + 'run-task-started-by': 'someJoe', + 'run-task-subnets': 'a,b', + 'run-task-security-groups': 'c,d', + 'run-task-container-overrides': JSON.stringify([{ name: 'someapp', command: 'somecmd' }]), + 'run-task-tags': '[{"key": "project", "value": "myproject"}]', + 'run-task-capacity-provider-strategy': '[{"capacityProvider":"FARGATE_SPOT","weight":1}]' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1257,24 +1292,22 @@ describe('Deploy to ECS', () => { }); test('run task and service ', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('somecluster') // cluster - .mockReturnValueOnce('true') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('') // enable-ecs-managed-tags - .mockReturnValueOnce('') // propagate-tags - .mockReturnValueOnce('true') // run-task - .mockReturnValueOnce('false') // wait-for-task-stopped - .mockReturnValueOnce('someJoe') // run-task-started-by - .mockReturnValueOnce('EC2') // run-task-launch-type - .mockReturnValueOnce('a,b') // run-task-subnet-ids - .mockReturnValueOnce('c,d') // run-task-security-group-ids - .mockReturnValueOnce(JSON.stringify([{ name: 'someapp', command: 'somecmd' }])); // run-task-container-overrides + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'somecluster', + 'wait-for-service-stability': 'true', + 'run-task': 'true', + 'wait-for-task-stopped': 'false', + 'run-task-started-by': 'someJoe', + 'run-task-launch-type': 'EC2', + 'run-task-subnets': 'a,b', + 'run-task-security-groups': 'c,d', + 'run-task-container-overrides': JSON.stringify([{ name: 'someapp', command: 'somecmd' }]) + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1308,19 +1341,15 @@ describe('Deploy to ECS', () => { }); test('run task and wait for it to stop', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('') // service - .mockReturnValueOnce('somecluster') // cluster - .mockReturnValueOnce('') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('') // enable-ecs-managed-tags - .mockReturnValueOnce('') // propagate-tags - .mockReturnValueOnce('true') // run-task - .mockReturnValueOnce('true'); // wait-for-task-stopped + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'cluster': 'somecluster', + 'run-task': 'true', + 'wait-for-task-stopped': 'true' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1333,25 +1362,19 @@ describe('Deploy to ECS', () => { }); test('run task in bridge network mode', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('somecluster') // cluster - .mockReturnValueOnce('true') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // enable-ecs-managed-tags - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('') // propagate-tags - .mockReturnValueOnce('true') // run-task - .mockReturnValueOnce('true') // wait-for-task-stopped - .mockReturnValueOnce('someJoe') // run-task-started-by - .mockReturnValueOnce('EC2') // run-task-launch-type - .mockReturnValueOnce('') // run-task-subnet-ids - .mockReturnValueOnce('') // run-task-security-group-ids - .mockReturnValueOnce('') // run-task-container-overrides - .mockReturnValueOnce('') // run-task-assign-public-IP + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'somecluster', + 'wait-for-service-stability': 'true', + 'run-task': 'true', + 'wait-for-task-stopped': 'true', + 'run-task-started-by': 'someJoe', + 'run-task-launch-type': 'EC2' + }; + return values[input] || ''; + }); await run(); expect(mockRunTask).toHaveBeenCalledWith({ @@ -1368,18 +1391,15 @@ describe('Deploy to ECS', () => { }); test('run task with setting true to enableECSManagedTags', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('') // service - .mockReturnValueOnce('somecluster') // cluster - .mockReturnValueOnce('') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('true') // enable-ecs-managed-tags - .mockReturnValueOnce('') // propagate-tags - .mockReturnValueOnce('true'); // run-task + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'cluster': 'somecluster', + 'enable-ecs-managed-tags': 'true', + 'run-task': 'true' + }; + return values[input] || ''; + }); await run(); expect(mockRunTask).toHaveBeenCalledWith({ @@ -1396,18 +1416,15 @@ describe('Deploy to ECS', () => { }); test('run task with setting false to enableECSManagedTags', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('') // service - .mockReturnValueOnce('somecluster') // cluster - .mockReturnValueOnce('') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('false') // enable-ecs-managed-tags - .mockReturnValueOnce('') // propagate-tags - .mockReturnValueOnce('true'); // run-task + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'cluster': 'somecluster', + 'enable-ecs-managed-tags': 'false', + 'run-task': 'true' + }; + return values[input] || ''; + }); await run(); expect(mockRunTask).toHaveBeenCalledWith({ @@ -1424,19 +1441,15 @@ describe('Deploy to ECS', () => { }); test('error is caught if run task fails with (wait-for-task-stopped: true)', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('') // service - .mockReturnValueOnce('somecluster') // cluster - .mockReturnValueOnce('') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('') // enable-ecs-managed-tags - .mockReturnValueOnce('') // propagate-tags - .mockReturnValueOnce('true') // run-task - .mockReturnValueOnce('true'); // wait-for-task-stopped + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'cluster': 'somecluster', + 'run-task': 'true', + 'wait-for-task-stopped': 'true' + }; + return values[input] || ''; + }); mockRunTask.mockImplementation( () => Promise.resolve({ @@ -1467,19 +1480,15 @@ describe('Deploy to ECS', () => { }); test('error is caught if run task fails with (wait-for-task-stopped: false) and with service', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('') // service - .mockReturnValueOnce('somecluster') // cluster - .mockReturnValueOnce('') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('') // enable-ecs-managed-tags - .mockReturnValueOnce('') // propagate-tags - .mockReturnValueOnce('true') // run-task - .mockReturnValueOnce('false'); // wait-for-task-stopped + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'cluster': 'somecluster', + 'run-task': 'true', + 'wait-for-task-stopped': 'false' + }; + return values[input] || ''; + }); mockRunTask.mockImplementation( () => Promise.resolve({ @@ -1590,17 +1599,16 @@ describe('Deploy to ECS', () => { }); test('propagate service tags from service', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789') // cluster - .mockReturnValueOnce('false') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('') // enable-ecs-managed-tags - .mockReturnValueOnce('SERVICE'); // propagate-tags + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'cluster-789', + 'wait-for-service-stability': 'false', + 'propagate-tags': 'SERVICE' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1622,17 +1630,17 @@ describe('Deploy to ECS', () => { }); test('update service with setting true to enableECSManagedTags', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789') // cluster - .mockReturnValueOnce('false') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('true') // enable-ecs-managed-tags - .mockReturnValueOnce('SERVICE'); // propagate-tags + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'cluster-789', + 'wait-for-service-stability': 'false', + 'enable-ecs-managed-tags': 'true', + 'propagate-tags': 'SERVICE' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1654,17 +1662,17 @@ describe('Deploy to ECS', () => { }); test('update service with setting false to enableECSManagedTags', async () => { - core.getInput = jest - .fn() - .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456') // service - .mockReturnValueOnce('cluster-789') // cluster - .mockReturnValueOnce('false') // wait-for-service-stability - .mockReturnValueOnce('') // wait-for-minutes - .mockReturnValueOnce('') // force-new-deployment - .mockReturnValueOnce('') // desired-count - .mockReturnValueOnce('false') // enable-ecs-managed-tags - .mockReturnValueOnce('SERVICE'); // propagate-tags + core.getInput = jest.fn(input => { + const values = { + 'task-definition': 'task-definition.json', + 'service': 'service-456', + 'cluster': 'cluster-789', + 'wait-for-service-stability': 'false', + 'enable-ecs-managed-tags': 'false', + 'propagate-tags': 'SERVICE' + }; + return values[input] || ''; + }); await run(); expect(core.setFailed).toHaveBeenCalledTimes(0);