2021-03-27 22:34:09 +00:00
|
|
|
import * as SDK from 'aws-sdk';
|
|
|
|
|
import { nanoid } from 'nanoid';
|
2021-03-27 22:45:16 +00:00
|
|
|
import * as fs from 'fs';
|
|
|
|
|
import * as core from '@actions/core';
|
|
|
|
|
import * as zlib from 'zlib';
|
2021-03-27 22:34:09 +00:00
|
|
|
|
|
|
|
|
class AWS {
|
|
|
|
|
static async runBuildJob(buildParameters, baseImage) {
|
2021-03-28 23:17:18 +00:00
|
|
|
try {
|
2021-03-28 23:57:35 +00:00
|
|
|
const buildUid = nanoid();
|
2021-04-03 00:19:00 +00:00
|
|
|
|
|
|
|
|
core.info("starting part 1/4 (clone from github and restore cache)");
|
2021-03-28 23:17:18 +00:00
|
|
|
await this.run(
|
|
|
|
|
buildUid,
|
|
|
|
|
buildParameters.awsStackName,
|
|
|
|
|
'alpine/git',
|
|
|
|
|
['/bin/sh'],
|
|
|
|
|
[
|
|
|
|
|
'-c',
|
|
|
|
|
`apk update;
|
2021-04-02 23:22:27 +00:00
|
|
|
apk add zip;
|
2021-03-27 22:34:09 +00:00
|
|
|
apk add git-lfs;
|
|
|
|
|
apk add jq;
|
|
|
|
|
ls;
|
2021-04-02 23:26:08 +00:00
|
|
|
git clone https://${process.env.GITHUB_TOKEN}@github.com/${process.env.GITHUB_REPOSITORY}.git ${buildUid}/repo;
|
|
|
|
|
git clone https://${process.env.GITHUB_TOKEN}@github.com/game-ci/unity-builder.git ${buildUid}/builder;
|
2021-04-03 00:15:24 +00:00
|
|
|
|
|
|
|
|
if [ ! -d "cache" ]; then
|
|
|
|
|
mkdir "cache"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
cd cache
|
2021-04-03 00:16:56 +00:00
|
|
|
ls
|
|
|
|
|
|
|
|
|
|
echo ''
|
|
|
|
|
|
2021-04-03 00:15:24 +00:00
|
|
|
latest=$(ls -t | head -1)
|
2021-04-03 00:16:56 +00:00
|
|
|
echo $latest
|
2021-04-03 00:15:24 +00:00
|
|
|
if [ -f $latest ]; then
|
2021-04-02 23:23:05 +00:00
|
|
|
echo "Cache exists"
|
2021-04-03 00:20:39 +00:00
|
|
|
zip -r $latest ../${buildUid}/repo/Library/.
|
2021-04-02 23:27:04 +00:00
|
|
|
else
|
2021-04-02 23:23:05 +00:00
|
|
|
echo "Cache does not exist"
|
2021-04-02 23:22:27 +00:00
|
|
|
fi
|
2021-04-03 00:15:24 +00:00
|
|
|
|
|
|
|
|
cd ..
|
|
|
|
|
|
2021-03-27 22:34:09 +00:00
|
|
|
cd ${buildUid}/repo;
|
|
|
|
|
git checkout $GITHUB_SHA;
|
2021-03-28 23:17:18 +00:00
|
|
|
`,
|
|
|
|
|
],
|
|
|
|
|
'/data',
|
|
|
|
|
'/data/',
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
name: 'GITHUB_SHA',
|
|
|
|
|
value: process.env.GITHUB_SHA,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'GithubToken',
|
|
|
|
|
ParameterValue: buildParameters.githubToken,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
);
|
2021-04-03 00:19:00 +00:00
|
|
|
|
|
|
|
|
core.info("starting part 2/4 (build)");
|
2021-03-28 23:17:18 +00:00
|
|
|
await this.run(
|
|
|
|
|
buildUid,
|
|
|
|
|
buildParameters.awsStackName,
|
|
|
|
|
baseImage.toString(),
|
|
|
|
|
['/bin/sh'],
|
|
|
|
|
[
|
|
|
|
|
'-c',
|
|
|
|
|
`
|
2021-04-02 22:40:38 +00:00
|
|
|
cp -R /data/${buildUid}/builder/dist/default-build-script/ /UnityBuilderAction;
|
|
|
|
|
cp -R /data/${buildUid}/builder/dist/entrypoint.sh /entrypoint.sh;
|
|
|
|
|
cp -R /data/${buildUid}/builder/dist/steps/ /steps;
|
2021-03-27 22:34:09 +00:00
|
|
|
ls;
|
|
|
|
|
chmod -R +x /entrypoint.sh;
|
|
|
|
|
chmod -R +x /steps;
|
|
|
|
|
/entrypoint.sh;
|
|
|
|
|
ls
|
2021-03-28 23:17:18 +00:00
|
|
|
`,
|
|
|
|
|
],
|
|
|
|
|
'/data',
|
|
|
|
|
`/data/${buildUid}/repo/`,
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
name: 'GITHUB_WORKSPACE',
|
|
|
|
|
value: `/data/${buildUid}/repo/`,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'PROJECT_PATH',
|
|
|
|
|
value: buildParameters.projectPath,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'BUILD_PATH',
|
|
|
|
|
value: buildParameters.buildPath,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'BUILD_FILE',
|
|
|
|
|
value: buildParameters.buildFile,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'BUILD_NAME',
|
|
|
|
|
value: buildParameters.buildName,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'BUILD_METHOD',
|
|
|
|
|
value: buildParameters.buildMethod,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'CUSTOM_PARAMETERS',
|
|
|
|
|
value: buildParameters.customParameters,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'BUILD_TARGET',
|
|
|
|
|
value: buildParameters.platform,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'ANDROID_VERSION_CODE',
|
|
|
|
|
value: buildParameters.androidVersionCode.toString(),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'ANDROID_KEYSTORE_NAME',
|
|
|
|
|
value: buildParameters.androidKeystoreName,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'ANDROID_KEYALIAS_NAME',
|
|
|
|
|
value: buildParameters.androidKeyaliasName,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'GithubToken',
|
|
|
|
|
ParameterValue: buildParameters.githubToken,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'UnityLicense',
|
|
|
|
|
ParameterValue: process.env.UNITY_LICENSE ? process.env.UNITY_LICENSE : '0',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'UnityEmail',
|
|
|
|
|
ParameterValue: process.env.UNITY_EMAIL ? process.env.UNITY_EMAIL : '0',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'UnityPassword',
|
|
|
|
|
ParameterValue: process.env.UNITY_PASSWORD ? process.env.UNITY_PASSWORD : '0',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'UnitySerial',
|
|
|
|
|
ParameterValue: process.env.UNITY_SERIAL ? process.env.UNITY_SERIAL : '0',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'AndroidKeystoreBase64',
|
|
|
|
|
ParameterValue: buildParameters.androidKeystoreBase64 ? buildParameters.androidKeystoreBase64 : '0',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'AndroidKeystorePass',
|
|
|
|
|
ParameterValue: buildParameters.androidKeystorePass ? buildParameters.androidKeystorePass : '0',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'AndroidKeyAliasPass',
|
|
|
|
|
ParameterValue: buildParameters.androidKeyaliasPass ? buildParameters.androidKeyaliasPass : '0',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
);
|
2021-04-03 00:19:00 +00:00
|
|
|
core.info("starting part 3/4 (zip and publish latest Library to cache)");
|
2021-03-28 23:17:18 +00:00
|
|
|
// Cleanup
|
|
|
|
|
await this.run(
|
|
|
|
|
buildUid,
|
|
|
|
|
buildParameters.awsStackName,
|
|
|
|
|
'alpine',
|
|
|
|
|
['/bin/sh'],
|
|
|
|
|
[
|
|
|
|
|
'-c',
|
|
|
|
|
`
|
2021-03-27 22:34:09 +00:00
|
|
|
apk update;
|
|
|
|
|
apk add zip
|
2021-04-03 00:20:10 +00:00
|
|
|
zip -r ./${buildUid}/Library/. ./cache/lib-${buildUid}.zip
|
2021-03-27 22:34:09 +00:00
|
|
|
zip -r ./${buildUid}/output.zip ./${buildUid}/repo/build
|
|
|
|
|
ls
|
2021-03-28 23:17:18 +00:00
|
|
|
`,
|
|
|
|
|
],
|
|
|
|
|
'/data',
|
|
|
|
|
'/data/',
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
name: 'GITHUB_SHA',
|
|
|
|
|
value: process.env.GITHUB_SHA,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'GithubToken',
|
|
|
|
|
ParameterValue: buildParameters.githubToken,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
);
|
2021-04-03 00:19:00 +00:00
|
|
|
|
|
|
|
|
core.info("starting part 4/4 (upload to s3)");
|
2021-03-28 23:17:18 +00:00
|
|
|
await this.run(
|
|
|
|
|
buildUid,
|
|
|
|
|
buildParameters.awsStackName,
|
|
|
|
|
'amazon/aws-cli',
|
|
|
|
|
['/bin/sh'],
|
|
|
|
|
[
|
|
|
|
|
'-c',
|
|
|
|
|
`
|
2021-04-03 00:29:47 +00:00
|
|
|
aws s3 cp ./${buildUid}/output.zip s3://game-ci-storage/${buildUid}.zip
|
|
|
|
|
aws s3 cp ./cache/lib-${buildUid}.zip s3://game-ci-storage/cache/lib-${buildUid}.zip
|
2021-03-27 22:34:09 +00:00
|
|
|
rm -r ${buildUid}
|
|
|
|
|
ls
|
2021-03-28 23:17:18 +00:00
|
|
|
`,
|
|
|
|
|
],
|
|
|
|
|
'/data',
|
|
|
|
|
'/data/',
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
name: 'GITHUB_SHA',
|
|
|
|
|
value: process.env.GITHUB_SHA,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'AWS_DEFAULT_REGION',
|
|
|
|
|
value: process.env.AWS_DEFAULT_REGION,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'GithubToken',
|
|
|
|
|
ParameterValue: buildParameters.githubToken,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'AWSAccessKeyID',
|
|
|
|
|
ParameterValue: process.env.AWS_ACCESS_KEY_ID,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'AWSSecretAccessKey',
|
|
|
|
|
ParameterValue: process.env.AWS_SECRET_ACCESS_KEY,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
} catch (error) {
|
2021-03-27 22:34:09 +00:00
|
|
|
core.setFailed(error);
|
|
|
|
|
core.error(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-28 23:17:18 +00:00
|
|
|
static async run(
|
|
|
|
|
buildUid: string,
|
|
|
|
|
stackName: string,
|
|
|
|
|
image: string,
|
|
|
|
|
entrypoint: string[],
|
|
|
|
|
commands,
|
|
|
|
|
mountdir,
|
|
|
|
|
workingdir,
|
|
|
|
|
environment,
|
|
|
|
|
secrets,
|
|
|
|
|
) {
|
2021-03-27 22:34:09 +00:00
|
|
|
const ECS = new SDK.ECS();
|
|
|
|
|
const CF = new SDK.CloudFormation();
|
|
|
|
|
|
2021-04-03 00:15:24 +00:00
|
|
|
const taskDef = await this.setupCloudFormations(
|
|
|
|
|
CF,
|
|
|
|
|
buildUid,
|
|
|
|
|
stackName,
|
|
|
|
|
image,
|
|
|
|
|
entrypoint,
|
|
|
|
|
commands,
|
|
|
|
|
mountdir,
|
|
|
|
|
workingdir,
|
|
|
|
|
secrets,
|
|
|
|
|
);
|
2021-03-27 22:34:09 +00:00
|
|
|
|
2021-04-03 00:15:24 +00:00
|
|
|
await this.runTask(taskDef, ECS, CF, environment, buildUid);
|
|
|
|
|
|
|
|
|
|
await this.cleanupResources(CF, taskDef);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static async setupCloudFormations(
|
|
|
|
|
CF,
|
|
|
|
|
buildUid: string,
|
|
|
|
|
stackName: string,
|
|
|
|
|
image: string,
|
|
|
|
|
entrypoint: string[],
|
|
|
|
|
commands,
|
|
|
|
|
mountdir,
|
|
|
|
|
workingdir,
|
|
|
|
|
secrets,
|
|
|
|
|
) {
|
|
|
|
|
const taskDefStackName = `${stackName}-taskDef-${image}-${buildUid}`.toString().replace(/[^\da-z]/gi, '');
|
|
|
|
|
const taskDefCloudFormation = fs.readFileSync(`${__dirname}/task-def-formation.yml`, 'utf8');
|
|
|
|
|
await CF.createStack({
|
|
|
|
|
StackName: taskDefStackName,
|
|
|
|
|
TemplateBody: taskDefCloudFormation,
|
|
|
|
|
Parameters: [
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'ImageUrl',
|
|
|
|
|
ParameterValue: image,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'ServiceName',
|
|
|
|
|
ParameterValue: taskDefStackName,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'Command',
|
|
|
|
|
ParameterValue: commands.join(','),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'EntryPoint',
|
|
|
|
|
ParameterValue: entrypoint.join(','),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'WorkingDirectory',
|
|
|
|
|
ParameterValue: workingdir,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'EFSMountDirectory',
|
|
|
|
|
ParameterValue: mountdir,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'BUILDID',
|
|
|
|
|
ParameterValue: buildUid,
|
|
|
|
|
},
|
|
|
|
|
...secrets,
|
|
|
|
|
],
|
|
|
|
|
}).promise();
|
|
|
|
|
core.info('Creating build cluster...');
|
2021-03-27 22:34:09 +00:00
|
|
|
|
2021-04-03 00:15:24 +00:00
|
|
|
const taskDefStackNameTTL = `${taskDefStackName}-ttl`;
|
|
|
|
|
const ttlCloudFormation = fs.readFileSync(`${__dirname}/cloudformation-stack-ttl.yml`, 'utf8');
|
|
|
|
|
await CF.createStack({
|
|
|
|
|
StackName: taskDefStackNameTTL,
|
|
|
|
|
TemplateBody: ttlCloudFormation,
|
|
|
|
|
Capabilities: ['CAPABILITY_IAM'],
|
|
|
|
|
Parameters: [
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'StackName',
|
|
|
|
|
ParameterValue: taskDefStackName,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'DeleteStackName',
|
|
|
|
|
ParameterValue: taskDefStackNameTTL,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'TTL',
|
|
|
|
|
ParameterValue: '100',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ParameterKey: 'BUILDID',
|
|
|
|
|
ParameterValue: buildUid,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}).promise();
|
|
|
|
|
core.info('Creating cleanup cluster...');
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
core.error(error);
|
|
|
|
|
}
|
2021-03-27 22:34:09 +00:00
|
|
|
const taskDefResources = await CF.describeStackResources({
|
2021-04-03 00:15:24 +00:00
|
|
|
StackName: taskDefStackName,
|
2021-03-27 22:34:09 +00:00
|
|
|
}).promise();
|
|
|
|
|
|
2021-03-28 20:32:52 +00:00
|
|
|
const baseResources = await CF.describeStackResources({ StackName: stackName }).promise();
|
2021-03-27 22:34:09 +00:00
|
|
|
|
2021-04-03 00:15:24 +00:00
|
|
|
core.info('Build cluster created successfully (skipping waiting for cleanup cluster to start)');
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
taskDefStackName,
|
|
|
|
|
taskDefCloudFormation,
|
|
|
|
|
taskDefStackNameTTL,
|
|
|
|
|
ttlCloudFormation,
|
|
|
|
|
taskDefResources,
|
|
|
|
|
baseResources,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static async runTask(taskDef, ECS, CF, environment, buildUid) {
|
2021-03-28 23:17:18 +00:00
|
|
|
const clusterName =
|
2021-04-03 00:15:24 +00:00
|
|
|
taskDef.baseResources.StackResources?.find((x) => x.LogicalResourceId === 'ECSCluster')?.PhysicalResourceId || '';
|
|
|
|
|
const taskDefinition = taskDef.taskDefResources.StackResources?.find((x) => x.LogicalResourceId === 'TaskDefinition')
|
|
|
|
|
?.PhysicalResourceId || '';
|
|
|
|
|
const SubnetOne = taskDef.baseResources.StackResources?.find((x) => x.LogicalResourceId === 'PublicSubnetOne')
|
|
|
|
|
?.PhysicalResourceId || '';
|
|
|
|
|
const SubnetTwo = taskDef.baseResources.StackResources?.find((x) => x.LogicalResourceId === 'PublicSubnetTwo')
|
|
|
|
|
?.PhysicalResourceId || '';
|
|
|
|
|
const ContainerSecurityGroup = taskDef.baseResources.StackResources?.find((x) => x.LogicalResourceId === 'ContainerSecurityGroup')
|
|
|
|
|
?.PhysicalResourceId || '';
|
|
|
|
|
const streamName =
|
|
|
|
|
taskDef.taskDefResources.StackResources?.find((x) => x.LogicalResourceId === 'KinesisStream')
|
|
|
|
|
?.PhysicalResourceId || '';
|
|
|
|
|
|
2021-03-28 23:57:35 +00:00
|
|
|
const task = await ECS.runTask({
|
|
|
|
|
cluster: clusterName,
|
2021-04-03 00:15:24 +00:00
|
|
|
taskDefinition: taskDefinition,
|
2021-03-28 23:57:35 +00:00
|
|
|
platformVersion: '1.4.0',
|
|
|
|
|
overrides: {
|
|
|
|
|
containerOverrides: [
|
|
|
|
|
{
|
2021-04-02 23:46:48 +00:00
|
|
|
name: taskDef.taskDefStackName,
|
2021-03-28 23:57:35 +00:00
|
|
|
environment: [...environment, { name: 'BUILDID', value: buildUid }],
|
2021-03-28 23:17:18 +00:00
|
|
|
},
|
2021-03-28 23:57:35 +00:00
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
launchType: 'FARGATE',
|
|
|
|
|
networkConfiguration: {
|
|
|
|
|
awsvpcConfiguration: {
|
2021-04-03 00:15:24 +00:00
|
|
|
subnets: [ SubnetOne, SubnetTwo ],
|
2021-03-28 23:57:35 +00:00
|
|
|
assignPublicIp: 'ENABLED',
|
2021-04-03 00:15:24 +00:00
|
|
|
securityGroups: [ ContainerSecurityGroup ],
|
2021-03-28 23:17:18 +00:00
|
|
|
},
|
2021-03-27 22:34:09 +00:00
|
|
|
},
|
2021-03-28 23:57:35 +00:00
|
|
|
}).promise();
|
2021-03-27 22:34:09 +00:00
|
|
|
|
|
|
|
|
core.info('Build job is starting');
|
2021-04-03 00:15:24 +00:00
|
|
|
const taskArn = task.tasks?.[0].taskArn || '';
|
2021-03-27 22:34:09 +00:00
|
|
|
|
|
|
|
|
try {
|
2021-04-03 00:15:24 +00:00
|
|
|
await ECS.waitFor('tasksRunning', { tasks: [taskArn], cluster: clusterName }).promise();
|
2021-03-27 22:34:09 +00:00
|
|
|
} catch (error) {
|
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
2021-03-28 23:57:35 +00:00
|
|
|
const describeTasks = await ECS.describeTasks({
|
2021-04-03 00:15:24 +00:00
|
|
|
tasks: [taskArn],
|
2021-03-27 22:34:09 +00:00
|
|
|
cluster: clusterName,
|
|
|
|
|
}).promise();
|
2021-03-28 23:17:18 +00:00
|
|
|
core.info(`Build job has ended ${describeTasks.tasks?.[0].containers?.[0].lastStatus}`);
|
2021-03-27 22:34:09 +00:00
|
|
|
core.setFailed(error);
|
|
|
|
|
core.error(error);
|
|
|
|
|
}
|
|
|
|
|
core.info(`Build job is running`);
|
2021-04-03 00:15:24 +00:00
|
|
|
await this.streamLogsUntilTaskStops(ECS, CF, taskDef, clusterName, taskArn, streamName);
|
|
|
|
|
await ECS.waitFor('tasksStopped', { cluster: clusterName, tasks: [taskArn] }).promise();
|
|
|
|
|
const exitCode = (
|
|
|
|
|
await ECS.describeTasks({
|
|
|
|
|
tasks: [taskArn],
|
|
|
|
|
cluster: clusterName,
|
|
|
|
|
}).promise()
|
|
|
|
|
).tasks?.[0].containers?.[0].exitCode;
|
|
|
|
|
if (exitCode !== 0) {
|
2021-04-03 00:28:18 +00:00
|
|
|
core.error(`job failed with exit code ${exitCode}`);
|
2021-04-03 00:15:24 +00:00
|
|
|
} else {
|
2021-04-03 00:28:18 +00:00
|
|
|
core.info(`Build job has finished successfully`);
|
2021-04-03 00:15:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
2021-03-27 22:34:09 +00:00
|
|
|
|
2021-04-03 00:15:24 +00:00
|
|
|
static async streamLogsUntilTaskStops(ECS, CF, taskDef, clusterName, taskArn, kinesisStreamName) {
|
2021-03-27 22:34:09 +00:00
|
|
|
// watching logs
|
|
|
|
|
const kinesis = new SDK.Kinesis();
|
|
|
|
|
|
|
|
|
|
const getTaskStatus = async () => {
|
|
|
|
|
const tasks = await ECS.describeTasks({
|
|
|
|
|
cluster: clusterName,
|
2021-04-03 00:15:24 +00:00
|
|
|
tasks: [taskArn],
|
2021-03-27 22:34:09 +00:00
|
|
|
}).promise();
|
|
|
|
|
return tasks.tasks?.[0].lastStatus;
|
|
|
|
|
};
|
|
|
|
|
|
2021-03-28 23:17:18 +00:00
|
|
|
const stream = await kinesis
|
2021-03-28 23:57:35 +00:00
|
|
|
.describeStream({
|
2021-04-03 00:15:24 +00:00
|
|
|
StreamName: kinesisStreamName,
|
2021-03-28 23:57:35 +00:00
|
|
|
})
|
2021-03-28 23:17:18 +00:00
|
|
|
.promise();
|
2021-03-27 22:34:09 +00:00
|
|
|
|
2021-03-28 23:17:18 +00:00
|
|
|
let iterator =
|
|
|
|
|
(
|
|
|
|
|
await kinesis
|
|
|
|
|
.getShardIterator({
|
|
|
|
|
ShardIteratorType: 'TRIM_HORIZON',
|
|
|
|
|
StreamName: stream.StreamDescription.StreamName,
|
|
|
|
|
ShardId: stream.StreamDescription.Shards[0].ShardId,
|
|
|
|
|
})
|
|
|
|
|
.promise()
|
|
|
|
|
).ShardIterator || '';
|
2021-03-27 22:34:09 +00:00
|
|
|
|
2021-04-02 23:46:48 +00:00
|
|
|
await CF.waitFor('stackCreateComplete', { StackName: taskDef.taskDefStackNameTTL }).promise();
|
2021-03-28 23:17:18 +00:00
|
|
|
|
2021-03-27 22:34:09 +00:00
|
|
|
core.info(`Task status is ${await getTaskStatus()}`);
|
|
|
|
|
|
2021-04-02 23:46:48 +00:00
|
|
|
const logBaseUrl = `https://console.aws.amazon.com/cloudwatch/home?region=${SDK.config.region}#logsV2:log-groups/${taskDef.taskDefStackName}`;
|
2021-03-27 22:34:09 +00:00
|
|
|
core.info(`You can also watch the logs at AWS Cloud Watch: ${logBaseUrl}`);
|
|
|
|
|
|
|
|
|
|
let readingLogs = true;
|
|
|
|
|
while (readingLogs) {
|
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
|
|
|
if ((await getTaskStatus()) !== 'RUNNING') {
|
|
|
|
|
readingLogs = false;
|
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 35000));
|
|
|
|
|
}
|
|
|
|
|
const records = await kinesis
|
|
|
|
|
.getRecords({
|
|
|
|
|
ShardIterator: iterator,
|
|
|
|
|
})
|
|
|
|
|
.promise();
|
2021-03-28 23:17:18 +00:00
|
|
|
iterator = records.NextShardIterator || '';
|
2021-03-27 22:34:09 +00:00
|
|
|
if (records.Records.length > 0) {
|
|
|
|
|
for (let index = 0; index < records.Records.length; index++) {
|
|
|
|
|
const json = JSON.parse(
|
2021-03-28 23:17:18 +00:00
|
|
|
zlib.gunzipSync(Buffer.from(records.Records[index].Data as string, 'base64')).toString('utf8'),
|
2021-03-27 22:34:09 +00:00
|
|
|
);
|
|
|
|
|
if (json.messageType === 'DATA_MESSAGE') {
|
|
|
|
|
for (let logEventsIndex = 0; logEventsIndex < json.logEvents.length; logEventsIndex++) {
|
|
|
|
|
core.info(json.logEvents[logEventsIndex].message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-03 00:15:24 +00:00
|
|
|
}
|
2021-03-27 22:34:09 +00:00
|
|
|
|
2021-04-03 00:15:24 +00:00
|
|
|
static async cleanupResources(CF, taskDef) {
|
2021-03-27 22:34:09 +00:00
|
|
|
await CF.deleteStack({
|
2021-04-02 23:46:48 +00:00
|
|
|
StackName: taskDef.taskDefStackName,
|
2021-03-27 22:34:09 +00:00
|
|
|
}).promise();
|
|
|
|
|
|
|
|
|
|
await CF.deleteStack({
|
2021-04-02 23:46:48 +00:00
|
|
|
StackName: taskDef.taskDefStackNameTTL,
|
2021-03-27 22:34:09 +00:00
|
|
|
}).promise();
|
|
|
|
|
|
|
|
|
|
await CF.waitFor('stackDeleteComplete', {
|
2021-04-02 23:46:48 +00:00
|
|
|
StackName: taskDef.taskDefStackName,
|
2021-03-27 22:34:09 +00:00
|
|
|
}).promise();
|
|
|
|
|
|
2021-04-02 23:06:47 +00:00
|
|
|
// Currently too slow and causes too much waiting
|
2021-04-02 23:11:34 +00:00
|
|
|
await CF.waitFor('stackDeleteComplete', {
|
2021-04-02 23:46:48 +00:00
|
|
|
StackName: taskDef.taskDefStackNameTTL,
|
2021-04-02 23:11:34 +00:00
|
|
|
}).promise();
|
2021-03-27 22:34:09 +00:00
|
|
|
|
|
|
|
|
core.info('Cleanup complete');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static onlog(batch) {
|
2021-03-28 23:57:35 +00:00
|
|
|
for (const log of batch) {
|
2021-03-27 22:34:09 +00:00
|
|
|
core.info(`log: ${log}`);
|
2021-03-28 23:57:35 +00:00
|
|
|
}
|
2021-03-27 22:34:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
2021-03-28 23:17:18 +00:00
|
|
|
export default AWS;
|