Skip to content

Commit 35bd757

Browse files
committed
feat: use existing task definition
1 parent 37ec59d commit 35bd757

File tree

3 files changed

+114
-17
lines changed

3 files changed

+114
-17
lines changed

action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ branding:
55
color: 'orange'
66
inputs:
77
task-definition:
8-
description: 'The path to the ECS task definition file to register'
8+
description: 'The path to the ECS task definition file to register or the name of the task definition family to use. If the task definition family is given, the action will use the latest ACTIVE revision of the task definition.'
99
required: true
1010
service:
1111
description: 'The name of the ECS service to deploy to. The action will only register the task definition if no service is given.'

index.js

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -269,23 +269,50 @@ async function run() {
269269
const forceNewDeployInput = core.getInput('force-new-deployment', { required: false }) || 'false';
270270
const forceNewDeployment = forceNewDeployInput.toLowerCase() === 'true';
271271

272-
// Register the task definition
273-
core.debug('Registering the task definition');
274272
const taskDefPath = path.isAbsolute(taskDefinitionFile) ?
275-
taskDefinitionFile :
276-
path.join(process.env.GITHUB_WORKSPACE, taskDefinitionFile);
277-
const fileContents = fs.readFileSync(taskDefPath, 'utf8');
278-
const taskDefContents = maintainValidObjects(removeIgnoredAttributes(cleanNullKeys(yaml.parse(fileContents))));
279-
let registerResponse;
280-
try {
281-
registerResponse = await ecs.registerTaskDefinition(taskDefContents).promise();
282-
} catch (error) {
283-
core.setFailed("Failed to register task definition in ECS: " + error.message);
284-
core.debug("Task definition contents:");
285-
core.debug(JSON.stringify(taskDefContents, undefined, 4));
286-
throw(error);
273+
taskDefinitionFile :
274+
path.join(process.env.GITHUB_WORKSPACE, taskDefinitionFile);
275+
276+
const isExistingTaskDef = fs.existsSync(taskDefPath);
277+
278+
let taskDefArn;
279+
280+
if (!isExistingTaskDef) {
281+
core.debug(`Searching for task definition ${taskDefinitionFile} in ECS`);
282+
try {
283+
const describeResponse = await ecs.describeTaskDefinition({
284+
taskDefinition: taskDefinitionFile
285+
}).promise();
286+
const taskDef = describeResponse.taskDefinition;
287+
288+
if (!taskDef) {
289+
throw new Error(`Task definition ${taskDefinitionFile} not found in ECS`);
290+
}
291+
292+
core.debug(`Found task definition ${taskDef.taskDefinitionArn}`);
293+
taskDefArn = taskDef.taskDefinitionArn;
294+
} catch (error) {
295+
core.setFailed("Failed to describe task definition in ECS: " + error.message);
296+
throw(error);
297+
}
287298
}
288-
const taskDefArn = registerResponse.taskDefinition.taskDefinitionArn;
299+
300+
if (isExistingTaskDef) {
301+
core.debug('Registering the task definition');
302+
const fileContents = fs.readFileSync(taskDefPath, 'utf8');
303+
const taskDefContents = maintainValidObjects(removeIgnoredAttributes(cleanNullKeys(yaml.parse(fileContents))));
304+
let registerResponse;
305+
try {
306+
registerResponse = await ecs.registerTaskDefinition(taskDefContents).promise();
307+
} catch (error) {
308+
core.setFailed("Failed to register task definition in ECS: " + error.message);
309+
core.debug("Task definition contents:");
310+
core.debug(JSON.stringify(taskDefContents, undefined, 4));
311+
throw(error);
312+
}
313+
taskDefArn = registerResponse.taskDefinition.taskDefinitionArn;
314+
}
315+
289316
core.setOutput('task-definition-arn', taskDefArn);
290317

291318
// Update the service with the new task definition

index.test.js

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ jest.mock('@actions/core');
77
jest.mock('fs', () => ({
88
promises: { access: jest.fn() },
99
readFileSync: jest.fn(),
10+
existsSync: jest.fn().mockReturnValue(true)
1011
}));
1112

1213
const mockEcsRegisterTaskDef = jest.fn();
1314
const mockEcsUpdateService = jest.fn();
1415
const mockEcsDescribeServices = jest.fn();
1516
const mockEcsWaiter = jest.fn();
17+
const mockEcsDescribeTaskDef = jest.fn();
1618
const mockCodeDeployCreateDeployment = jest.fn();
1719
const mockCodeDeployGetDeploymentGroup = jest.fn();
1820
const mockCodeDeployWaiter = jest.fn();
@@ -27,7 +29,8 @@ jest.mock('aws-sdk', () => {
2729
registerTaskDefinition: mockEcsRegisterTaskDef,
2830
updateService: mockEcsUpdateService,
2931
describeServices: mockEcsDescribeServices,
30-
waitFor: mockEcsWaiter
32+
waitFor: mockEcsWaiter,
33+
describeTaskDefinition: mockEcsDescribeTaskDef
3134
})),
3235
CodeDeploy: jest.fn(() => ({
3336
createDeployment: mockCodeDeployCreateDeployment,
@@ -86,6 +89,14 @@ describe('Deploy to ECS', () => {
8689
};
8790
});
8891

92+
mockEcsDescribeTaskDef.mockImplementation(() => {
93+
return {
94+
promise() {
95+
return Promise.resolve({ taskDefinition: { taskDefinitionArn: 'task:def:arn' } });
96+
}
97+
};
98+
})
99+
89100
mockEcsUpdateService.mockImplementation(() => {
90101
return {
91102
promise() {
@@ -151,6 +162,65 @@ describe('Deploy to ECS', () => {
151162
});
152163
});
153164

165+
test("try to get existing task definition ARN when user provides family instead of file", async () => {
166+
fs.existsSync.mockReturnValueOnce(false);
167+
168+
core.getInput = jest
169+
.fn()
170+
.mockReturnValueOnce('task-def-family')
171+
.mockReturnValueOnce('service-456')
172+
.mockReturnValueOnce('cluster-789');
173+
174+
await run();
175+
176+
expect(core.setFailed).toHaveBeenCalledTimes(0);
177+
expect(mockEcsDescribeTaskDef).toHaveBeenNthCalledWith(1, {
178+
taskDefinition: "task-def-family"
179+
});
180+
expect(mockEcsRegisterTaskDef).not.toHaveBeenCalled();
181+
expect(core.setOutput).toHaveBeenNthCalledWith(1, 'task-definition-arn', 'task:def:arn');
182+
expect(mockEcsDescribeServices).toHaveBeenNthCalledWith(1, {
183+
cluster: 'cluster-789',
184+
services: ['service-456']
185+
});
186+
expect(mockEcsUpdateService).toHaveBeenNthCalledWith(1, {
187+
cluster: 'cluster-789',
188+
service: 'service-456',
189+
taskDefinition: 'task:def:arn',
190+
forceNewDeployment: false
191+
});
192+
expect(mockEcsWaiter).toHaveBeenCalledTimes(0);
193+
expect(core.info).toBeCalledWith("Deployment started. Watch this deployment's progress in the Amazon ECS console: https://console.aws.amazon.com/ecs/home?region=fake-region#/clusters/cluster-789/services/service-456/events");
194+
});
195+
196+
test("should be able to throw an error when the task definition family is not found", async () => {
197+
fs.existsSync.mockReturnValueOnce(false);
198+
199+
core.getInput = jest
200+
.fn()
201+
.mockReturnValueOnce('task-def-family')
202+
.mockReturnValueOnce('service-456')
203+
.mockReturnValueOnce('cluster-789');
204+
205+
mockEcsDescribeTaskDef.mockImplementation(() => {
206+
return {
207+
promise() {
208+
return Promise.resolve({ taskDefinition: null });
209+
}
210+
};
211+
});
212+
213+
await run()
214+
215+
expect(mockEcsDescribeTaskDef).toHaveBeenNthCalledWith(1, {
216+
taskDefinition: "task-def-family"
217+
});
218+
expect(core.setFailed).toHaveBeenCalledTimes(2);
219+
expect(mockEcsRegisterTaskDef).not.toHaveBeenCalled();
220+
expect(core.setOutput).not.toHaveBeenNthCalledWith(1, 'task-definition-arn', 'task:def:arn');
221+
expect(core.info).not.toBeCalledWith("Deployment started. Watch this deployment's progress in the Amazon ECS console: https://console.aws.amazon.com/ecs/home?region=fake-region#/clusters/cluster-789/services/service-456/events");
222+
});
223+
154224
test('registers the task definition contents and updates the service', async () => {
155225
await run();
156226
expect(core.setFailed).toHaveBeenCalledTimes(0);

0 commit comments

Comments
 (0)