7
7
const path = __nccwpck_require__(1017);
8
8
const core = __nccwpck_require__(2186);
9
9
const { CodeDeploy, waitUntilDeploymentSuccessful } = __nccwpck_require__(6692);
10
- const { ECS, waitUntilServicesStable } = __nccwpck_require__(8209);
10
+ const { ECS, waitUntilServicesStable, waitUntilTasksStopped } = __nccwpck_require__(8209);
11
11
const yaml = __nccwpck_require__(4083);
12
12
const fs = __nccwpck_require__(7147);
13
13
const crypto = __nccwpck_require__(6113);
14
+ const { default: cluster } = __nccwpck_require__(5001);
14
15
15
16
const MAX_WAIT_MINUTES = 360; // 6 hours
16
17
const WAIT_DEFAULT_DELAY_SEC = 15;
@@ -27,15 +28,124 @@ const IGNORED_TASK_DEFINITION_ATTRIBUTES = [
27
28
'registeredBy'
28
29
];
29
30
31
+ //Code to run task outside of a service aka (also known as) a one-off task
32
+ async function runTask(ecs,clusterName, taskDefArn, waitForMinutes) {
33
+ core.info('Running task')
34
+
35
+ const waitForTask = core.getInput('wait-for-task-stopped', { required: false }) || 'false';
36
+ const startedBy = core.getInput('run-task-started-by', { required: false }) || 'GitHub-Actions';
37
+ const launchType = core.getInput('run-task-launch-type', { required: false })|| 'FARGATE';
38
+ const subnetIds = core.getInput('run-task-subnets', { required: false }) || '';
39
+ const securityGroupIds = core.getInput('run-task-security-groups', { required: false }) || '';
40
+ const containerOverrides = JSON.parse(core.getInput('run-task-container-overrides', { required: false }) || '[]');
41
+
42
+ let awsvpcConfiguration = {}
43
+
44
+
45
+ if (subnetIds != "") {
46
+ awsvpcConfiguration["subnets"] = subnetIds.split(',')
47
+ }
48
+
49
+ if (securityGroupIds != "") {
50
+ awsvpcConfiguration["securityGroups"] = securityGroupIds.split(',')
51
+ }
52
+
53
+ const runTaskResponse = await ecs.runTask({
54
+ startedBy: startedBy,
55
+ cluster: clusterName,
56
+ taskDefinition: taskDefArn,
57
+ overrides: {
58
+ containerOverrides: containerOverrides
59
+ },
60
+ launchType: launchType,
61
+ networkConfiguration: Object.keys(awsvpcConfiguration).length === 0 ? {} : { awsvpcConfiguration: awsvpcConfiguration },
62
+
63
+ });
64
+
65
+
66
+ core.debug(`Run task response ${JSON.stringify(runTaskResponse)}`)
67
+
68
+ const taskArns = runTaskResponse.tasks.map(task => task.taskArn);
69
+ core.setOutput('run-task-arn', taskArns);
70
+
71
+ const region = await ecs.config.region();
72
+ const consoleHostname = region.startsWith('cn') ? 'console.amazonaws.cn' : 'console.aws.amazon.com';
73
+
74
+ core.info(`Task running: https://${consoleHostname}/ecs/home?region=${region}#/clusters/${clusterName}/tasks`);
75
+
76
+
77
+ if (runTaskResponse.failures && runTaskResponse.failures.length > 0) {
78
+ const failure = runTaskResponse.failures[0];
79
+ throw new Error(`${failure.arn} is ${failure.reason}`);
80
+ }
81
+
82
+ // Wait for task to end
83
+ if (waitForTask && waitForTask.toLowerCase() === "true") {
84
+ await waitForTasksStopped(ecs, clusterName, taskArns, waitForMinutes)
85
+ await tasksExitCode(ecs, clusterName, taskArns)
86
+ } else {
87
+ core.debug('Not waiting for the task to stop');
88
+ }
89
+ }
90
+
91
+ // Poll tasks until they enter a stopped state
92
+ async function waitForTasksStopped(ecs, clusterName, taskArns, waitForMinutes) {
93
+ if (waitForMinutes > MAX_WAIT_MINUTES) {
94
+ waitForMinutes = MAX_WAIT_MINUTES;
95
+ }
96
+
97
+ core.info(`Waiting for tasks to stop. Will wait for ${waitForMinutes} minutes`);
98
+
99
+ const waitTaskResponse = await waitUntilTasksStopped({
100
+ client: ecs,
101
+ minDelay: WAIT_DEFAULT_DELAY_SEC,
102
+ maxWaitTime: waitForMinutes * 60,
103
+ }, {
104
+ cluster: clusterName,
105
+ tasks: taskArns,
106
+ });
107
+
108
+ core.debug(`Run task response ${JSON.stringify(waitTaskResponse)}`);
109
+ core.info('All tasks have stopped.');
110
+ }
111
+
112
+ // Check a task's exit code and fail the job on error
113
+ async function tasksExitCode(ecs, clusterName, taskArns) {
114
+ const describeResponse = await ecs.describeTasks({
115
+ cluster: clusterName,
116
+ tasks: taskArns
117
+ });
118
+
119
+ const containers = [].concat(...describeResponse.tasks.map(task => task.containers))
120
+ const exitCodes = containers.map(container => container.exitCode)
121
+ const reasons = containers.map(container => container.reason)
122
+
123
+ const failuresIdx = [];
124
+
125
+ exitCodes.filter((exitCode, index) => {
126
+ if (exitCode !== 0) {
127
+ failuresIdx.push(index)
128
+ }
129
+ })
130
+
131
+ const failures = reasons.filter((_, index) => failuresIdx.indexOf(index) !== -1)
132
+ if (failures.length > 0) {
133
+ throw new Error(`Run task failed: ${JSON.stringify(failures)}`);
134
+ }
135
+ }
136
+
137
+
30
138
// Deploy to a service that uses the 'ECS' deployment controller
31
139
async function updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment, desiredCount) {
32
140
core.debug('Updating the service');
141
+
33
142
let params = {
34
143
cluster: clusterName,
35
144
service: service,
36
145
taskDefinition: taskDefArn,
37
- forceNewDeployment: forceNewDeployment
146
+ forceNewDeployment: forceNewDeployment,
38
147
};
148
+
39
149
// Add the desiredCount property only if it is defined and a number.
40
150
if (!isNaN(desiredCount) && desiredCount !== undefined) {
41
151
params.desiredCount = desiredCount;
@@ -231,7 +341,7 @@ async function createCodeDeployDeployment(codedeploy, clusterName, service, task
231
341
};
232
342
// If it hasn't been set then we don't even want to pass it to the api call to maintain previous behaviour.
233
343
if (codeDeployDescription) {
234
- deploymentParams.description = codeDeployDescription
344
+ deploymentParams.description = ( codeDeployDescription.length <= 512) ? codeDeployDescription : `${codeDeployDescription.substring(0,511)}…`;
235
345
}
236
346
if (codeDeployConfig) {
237
347
deploymentParams.deploymentConfigName = codeDeployConfig
@@ -279,15 +389,15 @@ async function run() {
279
389
const cluster = core.getInput('cluster', { required: false });
280
390
const waitForService = core.getInput('wait-for-service-stability', { required: false });
281
391
let waitForMinutes = parseInt(core.getInput('wait-for-minutes', { required: false })) || 30;
392
+
282
393
if (waitForMinutes > MAX_WAIT_MINUTES) {
283
394
waitForMinutes = MAX_WAIT_MINUTES;
284
395
}
285
396
286
397
const forceNewDeployInput = core.getInput('force-new-deployment', { required: false }) || 'false';
287
398
const forceNewDeployment = forceNewDeployInput.toLowerCase() === 'true';
288
399
const desiredCount = parseInt((core.getInput('desired-count', {required: false})));
289
-
290
-
400
+
291
401
// Register the task definition
292
402
core.debug('Registering the task definition');
293
403
const taskDefPath = path.isAbsolute(taskDefinitionFile) ?
@@ -306,11 +416,21 @@ async function run() {
306
416
}
307
417
const taskDefArn = registerResponse.taskDefinition.taskDefinitionArn;
308
418
core.setOutput('task-definition-arn', taskDefArn);
419
+
420
+ // Run the task outside of the service
421
+ const clusterName = cluster ? cluster : 'default';
422
+ const shouldRunTaskInput = core.getInput('run-task', { required: false }) || 'false';
423
+ const shouldRunTask = shouldRunTaskInput.toLowerCase() === 'true';
424
+ core.debug(`shouldRunTask: ${shouldRunTask}`);
425
+
426
+ //run task
427
+ if (shouldRunTask) {
428
+ core.debug("Running one-off task...");
429
+ await runTask(ecs, clusterName, taskDefArn, waitForMinutes);
430
+ }
309
431
310
432
// Update the service with the new task definition
311
433
if (service) {
312
- const clusterName = cluster ? cluster : 'default';
313
-
314
434
// Determine the deployment controller
315
435
const describeResponse = await ecs.describeServices({
316
436
services: [service],
@@ -329,9 +449,12 @@ async function run() {
329
449
330
450
if (!serviceResponse.deploymentController || !serviceResponse.deploymentController.type || serviceResponse.deploymentController.type === 'ECS') {
331
451
// Service uses the 'ECS' deployment controller, so we can call UpdateService
452
+ core.debug('Updating service...');
332
453
await updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment, desiredCount);
454
+
333
455
} else if (serviceResponse.deploymentController.type === 'CODE_DEPLOY') {
334
456
// Service uses CodeDeploy, so we should start a CodeDeploy deployment
457
+ core.debug('Deploying service in the default cluster');
335
458
await createCodeDeployDeployment(codedeploy, clusterName, service, taskDefArn, waitForService, waitForMinutes);
336
459
} else {
337
460
throw new Error(`Unsupported deployment controller: ${serviceResponse.deploymentController.type}`);
@@ -61742,6 +61865,14 @@ module.exports = require("child_process");
61742
61865
61743
61866
/***/ }),
61744
61867
61868
+ /***/ 5001:
61869
+ /***/ ((module) => {
61870
+
61871
+ "use strict";
61872
+ module.exports = require("cluster");
61873
+
61874
+ /***/ }),
61875
+
61745
61876
/***/ 6206:
61746
61877
/***/ ((module) => {
61747
61878
0 commit comments