From e5f78d3088b0f4f96faca249870440a0001deaa3 Mon Sep 17 00:00:00 2001 From: Roman Kydybets <27759761+romankydybets@users.noreply.github.com> Date: Wed, 7 Feb 2024 19:08:52 +0100 Subject: [PATCH] feat: Add desired tasks (#505) * add desired count * add desired count * add desired count * fix test for desired count * small change * update dist/index.js * address feedback @iamhopaul123 * update dist/index.js --------- Co-authored-by: Adithya Kolla --- action.yml | 3 +++ dist/index.js | 16 +++++++++++---- index.js | 16 +++++++++++---- index.test.js | 55 +++++++++++++++++++++++++++++---------------------- 4 files changed, 58 insertions(+), 32 deletions(-) diff --git a/action.yml b/action.yml index c8e5b47ee..48e11ea12 100644 --- a/action.yml +++ b/action.yml @@ -7,6 +7,9 @@ inputs: task-definition: description: 'The path to the ECS task definition file to register' required: true + desired-count: + description: 'The number of instantiations of the task to place and keep running in your service.' + required: false service: description: 'The name of the ECS service to deploy to. The action will only register the task definition if no service is given.' required: false diff --git a/dist/index.js b/dist/index.js index 6e1dfd4bb..1a2cbace7 100644 --- a/dist/index.js +++ b/dist/index.js @@ -27,14 +27,19 @@ const IGNORED_TASK_DEFINITION_ATTRIBUTES = [ ]; // Deploy to a service that uses the 'ECS' deployment controller -async function updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment) { +async function updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment, desiredCount) { core.debug('Updating the service'); - await ecs.updateService({ + let params = { cluster: clusterName, service: service, taskDefinition: taskDefArn, forceNewDeployment: forceNewDeployment - }).promise(); + }; + // Add the desiredCount property only if it is defined and a number. + if (!isNaN(desiredCount) && desiredCount !== undefined) { + params.desiredCount = desiredCount; + } + await ecs.updateService(params).promise(); const consoleHostname = aws.config.region.startsWith('cn') ? 'console.amazonaws.cn' : 'console.aws.amazon.com'; @@ -275,6 +280,9 @@ async function run() { const forceNewDeployInput = core.getInput('force-new-deployment', { required: false }) || 'false'; const forceNewDeployment = forceNewDeployInput.toLowerCase() === 'true'; + const desiredCount = parseInt((core.getInput('desired-count', {required: false}))); + + // Register the task definition core.debug('Registering the task definition'); const taskDefPath = path.isAbsolute(taskDefinitionFile) ? @@ -316,7 +324,7 @@ async function run() { if (!serviceResponse.deploymentController || !serviceResponse.deploymentController.type || serviceResponse.deploymentController.type === 'ECS') { // Service uses the 'ECS' deployment controller, so we can call UpdateService - await updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment); + await updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment, desiredCount); } else if (serviceResponse.deploymentController.type === 'CODE_DEPLOY') { // Service uses CodeDeploy, so we should start a CodeDeploy deployment await createCodeDeployDeployment(codedeploy, clusterName, service, taskDefArn, waitForService, waitForMinutes); diff --git a/index.js b/index.js index 7f759a088..aafd6e4cf 100644 --- a/index.js +++ b/index.js @@ -21,14 +21,19 @@ const IGNORED_TASK_DEFINITION_ATTRIBUTES = [ ]; // Deploy to a service that uses the 'ECS' deployment controller -async function updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment) { +async function updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment, desiredCount) { core.debug('Updating the service'); - await ecs.updateService({ + let params = { cluster: clusterName, service: service, taskDefinition: taskDefArn, forceNewDeployment: forceNewDeployment - }).promise(); + }; + // Add the desiredCount property only if it is defined and a number. + if (!isNaN(desiredCount) && desiredCount !== undefined) { + params.desiredCount = desiredCount; + } + await ecs.updateService(params).promise(); const consoleHostname = aws.config.region.startsWith('cn') ? 'console.amazonaws.cn' : 'console.aws.amazon.com'; @@ -269,6 +274,9 @@ async function run() { const forceNewDeployInput = core.getInput('force-new-deployment', { required: false }) || 'false'; const forceNewDeployment = forceNewDeployInput.toLowerCase() === 'true'; + const desiredCount = parseInt((core.getInput('desired-count', {required: false}))); + + // Register the task definition core.debug('Registering the task definition'); const taskDefPath = path.isAbsolute(taskDefinitionFile) ? @@ -310,7 +318,7 @@ async function run() { if (!serviceResponse.deploymentController || !serviceResponse.deploymentController.type || serviceResponse.deploymentController.type === 'ECS') { // Service uses the 'ECS' deployment controller, so we can call UpdateService - await updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment); + await updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment, desiredCount); } else if (serviceResponse.deploymentController.type === 'CODE_DEPLOY') { // Service uses CodeDeploy, so we should start a CodeDeploy deployment await createCodeDeployDeployment(codedeploy, clusterName, service, taskDefArn, waitForService, waitForMinutes); diff --git a/index.test.js b/index.test.js index a032634b8..ba4f6ac97 100644 --- a/index.test.js +++ b/index.test.js @@ -687,14 +687,15 @@ describe('Deploy to ECS', () => { 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('/hello/appspec.json') // codedeploy-appspec - .mockReturnValueOnce('MyApplication') // codedeploy-application - .mockReturnValueOnce('MyDeploymentGroup'); // codedeploy-deployment-group + .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('/hello/appspec.json') // codedeploy-appspec + .mockReturnValueOnce('MyApplication') // codedeploy-application + .mockReturnValueOnce('MyDeploymentGroup') // codedeploy-deployment-group fs.readFileSync.mockReturnValue(` { @@ -887,7 +888,7 @@ describe('Deploy to ECS', () => { expect(core.info).toBeCalledWith("Deployment started. Watch this deployment's progress in the AWS CodeDeploy console: https://console.aws.amazon.com/codesuite/codedeploy/deployments/deployment-1?region=fake-region"); }); - test('registers the task definition contents at an absolute path', async () => { + test('registers the task definition contents at an absolute path', async () => { core.getInput = jest.fn().mockReturnValueOnce('/hello/task-definition.json'); fs.readFileSync.mockImplementation((pathInput, encoding) => { if (encoding != 'utf8') { @@ -908,13 +909,14 @@ describe('Deploy to ECS', () => { expect(core.setOutput).toHaveBeenNthCalledWith(1, 'task-definition-arn', 'task:def:arn'); }); - test('waits for the service to be stable', async () => { + 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('service-456') // service + .mockReturnValueOnce('cluster-789') // cluster + .mockReturnValueOnce('TRUE') // wait-for-service-stability + .mockReturnValueOnce(''); // desired count await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -945,10 +947,11 @@ describe('Deploy to ECS', () => { 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('service-456') // service + .mockReturnValueOnce('cluster-789') // cluster + .mockReturnValueOnce('TRUE') // wait-for-service-stability + .mockReturnValueOnce('60') // wait-for-minutes + .mockReturnValueOnce(''); // desired count await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -979,10 +982,11 @@ describe('Deploy to ECS', () => { 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('service-456') // service + .mockReturnValueOnce('cluster-789') // cluster + .mockReturnValueOnce('TRUE') // wait-for-service-stability + .mockReturnValueOnce('1000') // wait-for-minutes + .mockReturnValueOnce('abc'); // desired count is NaN await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1012,12 +1016,13 @@ describe('Deploy to ECS', () => { test('force new deployment', async () => { core.getInput = jest .fn() - .mockReturnValueOnce('task-definition.json') // task-definition + .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('true') // force-new-deployment + .mockReturnValueOnce('4'); // desired count is number await run(); expect(core.setFailed).toHaveBeenCalledTimes(0); @@ -1030,6 +1035,7 @@ describe('Deploy to ECS', () => { }); expect(mockEcsUpdateService).toHaveBeenNthCalledWith(1, { cluster: 'cluster-789', + desiredCount: 4, service: 'service-456', taskDefinition: 'task:def:arn', forceNewDeployment: true @@ -1040,7 +1046,8 @@ describe('Deploy to ECS', () => { core.getInput = jest .fn() .mockReturnValueOnce('task-definition.json') // task-definition - .mockReturnValueOnce('service-456'); // service + .mockReturnValueOnce('service-456') // service + .mockReturnValueOnce(''); // desired count await run(); expect(core.setFailed).toHaveBeenCalledTimes(0);