pull/235/head
mdugdale 2021-03-29 00:17:18 +01:00
parent aa0f813abd
commit 8da174c2a9
6 changed files with 327 additions and 306 deletions

89
dist/index.js vendored
View File

@ -239,7 +239,7 @@ class AWS {
git clone https://$GITHUB_TOKEN@github.com/webbertakken/unity-builder.git ${buildUid}/builder; git clone https://$GITHUB_TOKEN@github.com/webbertakken/unity-builder.git ${buildUid}/builder;
cd ${buildUid}/repo; cd ${buildUid}/repo;
git checkout $GITHUB_SHA; git checkout $GITHUB_SHA;
` `,
], '/data', '/data/', [ ], '/data', '/data/', [
{ {
name: 'GITHUB_SHA', name: 'GITHUB_SHA',
@ -251,7 +251,9 @@ class AWS {
ParameterValue: buildParameters.githubToken, ParameterValue: buildParameters.githubToken,
}, },
]); ]);
yield this.run(buildUid, buildParameters.awsStackName, baseImage.toString(), ['/bin/sh'], ['-c', ` yield this.run(buildUid, buildParameters.awsStackName, baseImage.toString(), ['/bin/sh'], [
'-c',
`
cp -r /data/${buildUid}/builder/action/default-build-script /UnityBuilderAction; cp -r /data/${buildUid}/builder/action/default-build-script /UnityBuilderAction;
cp -r /data/${buildUid}/builder/action/entrypoint.sh /entrypoint.sh; cp -r /data/${buildUid}/builder/action/entrypoint.sh /entrypoint.sh;
cp -r /data/${buildUid}/builder/action/steps /steps; cp -r /data/${buildUid}/builder/action/steps /steps;
@ -260,7 +262,8 @@ class AWS {
chmod -R +x /steps; chmod -R +x /steps;
/entrypoint.sh; /entrypoint.sh;
ls ls
`], '/data', `/data/${buildUid}/repo/`, [ `,
], '/data', `/data/${buildUid}/repo/`, [
{ {
name: 'GITHUB_WORKSPACE', name: 'GITHUB_WORKSPACE',
value: `/data/${buildUid}/repo/`, value: `/data/${buildUid}/repo/`,
@ -312,31 +315,31 @@ class AWS {
}, },
{ {
ParameterKey: 'UnityLicense', ParameterKey: 'UnityLicense',
ParameterValue: process.env.UNITY_LICENSE ? process.env.UNITY_LICENSE : '0' ParameterValue: process.env.UNITY_LICENSE ? process.env.UNITY_LICENSE : '0',
}, },
{ {
ParameterKey: 'UnityEmail', ParameterKey: 'UnityEmail',
ParameterValue: process.env.UNITY_EMAIL ? process.env.UNITY_EMAIL : '0' ParameterValue: process.env.UNITY_EMAIL ? process.env.UNITY_EMAIL : '0',
}, },
{ {
ParameterKey: 'UnityPassword', ParameterKey: 'UnityPassword',
ParameterValue: process.env.UNITY_PASSWORD ? process.env.UNITY_PASSWORD : '0' ParameterValue: process.env.UNITY_PASSWORD ? process.env.UNITY_PASSWORD : '0',
}, },
{ {
ParameterKey: 'UnitySerial', ParameterKey: 'UnitySerial',
ParameterValue: process.env.UNITY_SERIAL ? process.env.UNITY_SERIAL : '0' ParameterValue: process.env.UNITY_SERIAL ? process.env.UNITY_SERIAL : '0',
}, },
{ {
ParameterKey: 'AndroidKeystoreBase64', ParameterKey: 'AndroidKeystoreBase64',
ParameterValue: buildParameters.androidKeystoreBase64 ? buildParameters.androidKeystoreBase64 : '0' ParameterValue: buildParameters.androidKeystoreBase64 ? buildParameters.androidKeystoreBase64 : '0',
}, },
{ {
ParameterKey: 'AndroidKeystorePass', ParameterKey: 'AndroidKeystorePass',
ParameterValue: buildParameters.androidKeystorePass ? buildParameters.androidKeystorePass : '0' ParameterValue: buildParameters.androidKeystorePass ? buildParameters.androidKeystorePass : '0',
}, },
{ {
ParameterKey: 'AndroidKeyAliasPass', ParameterKey: 'AndroidKeyAliasPass',
ParameterValue: buildParameters.androidKeyaliasPass ? buildParameters.androidKeyaliasPass : '0' ParameterValue: buildParameters.androidKeyaliasPass ? buildParameters.androidKeyaliasPass : '0',
}, },
]); ]);
// Cleanup // Cleanup
@ -347,7 +350,7 @@ class AWS {
apk add zip apk add zip
zip -r ./${buildUid}/output.zip ./${buildUid}/repo/build zip -r ./${buildUid}/output.zip ./${buildUid}/repo/build
ls ls
` `,
], '/data', '/data/', [ ], '/data', '/data/', [
{ {
name: 'GITHUB_SHA', name: 'GITHUB_SHA',
@ -365,7 +368,7 @@ class AWS {
aws s3 cp ./${buildUid}/output.zip s3://game-ci-storage/${buildUid} aws s3 cp ./${buildUid}/output.zip s3://game-ci-storage/${buildUid}
rm -r ${buildUid} rm -r ${buildUid}
ls ls
` `,
], '/data', '/data/', [ ], '/data', '/data/', [
{ {
name: 'GITHUB_SHA', name: 'GITHUB_SHA',
@ -401,9 +404,7 @@ class AWS {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const ECS = new SDK.ECS(); const ECS = new SDK.ECS();
const CF = new SDK.CloudFormation(); const CF = new SDK.CloudFormation();
const taskDefStackName = `${stackName}-taskDef-${image}-${buildUid}` const taskDefStackName = `${stackName}-taskDef-${image}-${buildUid}`.toString().replace(/[^\da-z]/gi, '');
.toString()
.replace(/[^\da-z]/gi, '');
const taskDefCloudFormation = fs.readFileSync(`${__dirname}/task-def-formation.yml`, 'utf8'); const taskDefCloudFormation = fs.readFileSync(`${__dirname}/task-def-formation.yml`, 'utf8');
yield CF.createStack({ yield CF.createStack({
StackName: taskDefStackName, StackName: taskDefStackName,
@ -436,16 +437,16 @@ class AWS {
{ {
ParameterKey: 'BUILDID', ParameterKey: 'BUILDID',
ParameterValue: buildUid, ParameterValue: buildUid,
} },
].concat(secrets), ].concat(secrets),
}).promise(); }).promise();
core.info("Creating build cluster..."); core.info('Creating build cluster...');
const taskDefStackNameTTL = taskDefStackName + "-ttl"; const taskDefStackNameTTL = taskDefStackName + '-ttl';
const ttlCloudFormation = fs.readFileSync(`${__dirname}/cloudformation-stack-ttl.yml`, 'utf8'); const ttlCloudFormation = fs.readFileSync(`${__dirname}/cloudformation-stack-ttl.yml`, 'utf8');
yield CF.createStack({ yield CF.createStack({
StackName: taskDefStackNameTTL, StackName: taskDefStackNameTTL,
TemplateBody: ttlCloudFormation, TemplateBody: ttlCloudFormation,
Capabilities: ["CAPABILITY_IAM"], Capabilities: ['CAPABILITY_IAM'],
Parameters: [ Parameters: [
{ {
ParameterKey: 'StackName', ParameterKey: 'StackName',
@ -453,38 +454,37 @@ class AWS {
}, },
{ {
ParameterKey: 'TTL', ParameterKey: 'TTL',
ParameterValue: "100", ParameterValue: '100',
}, },
{ {
ParameterKey: 'BUILDID', ParameterKey: 'BUILDID',
ParameterValue: buildUid, ParameterValue: buildUid,
} },
], ],
}).promise(); }).promise();
core.info("Creating cleanup cluster..."); core.info('Creating cleanup cluster...');
try { try {
yield CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise(); yield CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise();
} }
catch (error) { catch (error) {
core.error(error); core.error(error);
} }
core.info("Cloud formation stack created"); core.info('Cloud formation stack created');
const taskDefResources = yield CF.describeStackResources({ const taskDefResources = yield CF.describeStackResources({
StackName: taskDefStackName, StackName: taskDefStackName,
}).promise(); }).promise();
const baseResources = yield CF.describeStackResources({ StackName: stackName }).promise(); const baseResources = yield CF.describeStackResources({ StackName: stackName }).promise();
const clusterName = ((_b = (_a = baseResources.StackResources) === null || _a === void 0 ? void 0 : _a.find((x) => x.LogicalResourceId === 'ECSCluster')) === null || _b === void 0 ? void 0 : _b.PhysicalResourceId) || ""; const clusterName = ((_b = (_a = baseResources.StackResources) === null || _a === void 0 ? void 0 : _a.find((x) => x.LogicalResourceId === 'ECSCluster')) === null || _b === void 0 ? void 0 : _b.PhysicalResourceId) || '';
const task = yield ECS.runTask({ const task = yield ECS.runTask({
cluster: clusterName, cluster: clusterName,
taskDefinition: ((_d = (_c = taskDefResources.StackResources) === null || _c === void 0 ? void 0 : _c.find((x) => x.LogicalResourceId === 'TaskDefinition')) === null || _d === void 0 ? void 0 : _d.PhysicalResourceId) || "", taskDefinition: ((_d = (_c = taskDefResources.StackResources) === null || _c === void 0 ? void 0 : _c.find((x) => x.LogicalResourceId === 'TaskDefinition')) === null || _d === void 0 ? void 0 : _d.PhysicalResourceId) ||
'',
platformVersion: '1.4.0', platformVersion: '1.4.0',
overrides: { overrides: {
containerOverrides: [ containerOverrides: [
{ {
name: taskDefStackName, name: taskDefStackName,
environment: environment.concat([ environment: environment.concat([{ name: 'BUILDID', value: buildUid }]),
{ name: 'BUILDID', value: buildUid }
]),
}, },
], ],
}, },
@ -492,24 +492,24 @@ class AWS {
networkConfiguration: { networkConfiguration: {
awsvpcConfiguration: { awsvpcConfiguration: {
subnets: [ subnets: [
((_f = (_e = baseResources.StackResources) === null || _e === void 0 ? void 0 : _e.find((x) => x.LogicalResourceId === 'PublicSubnetOne')) === null || _f === void 0 ? void 0 : _f.PhysicalResourceId) || "", ((_f = (_e = baseResources.StackResources) === null || _e === void 0 ? void 0 : _e.find((x) => x.LogicalResourceId === 'PublicSubnetOne')) === null || _f === void 0 ? void 0 : _f.PhysicalResourceId) || '',
((_h = (_g = baseResources.StackResources) === null || _g === void 0 ? void 0 : _g.find((x) => x.LogicalResourceId === 'PublicSubnetTwo')) === null || _h === void 0 ? void 0 : _h.PhysicalResourceId) || "", ((_h = (_g = baseResources.StackResources) === null || _g === void 0 ? void 0 : _g.find((x) => x.LogicalResourceId === 'PublicSubnetTwo')) === null || _h === void 0 ? void 0 : _h.PhysicalResourceId) || '',
], ],
assignPublicIp: 'ENABLED', assignPublicIp: 'ENABLED',
securityGroups: [ securityGroups: [
((_k = (_j = baseResources.StackResources) === null || _j === void 0 ? void 0 : _j.find((x) => x.LogicalResourceId === 'ContainerSecurityGroup')) === null || _k === void 0 ? void 0 : _k.PhysicalResourceId) || "", ((_k = (_j = baseResources.StackResources) === null || _j === void 0 ? void 0 : _j.find((x) => x.LogicalResourceId === 'ContainerSecurityGroup')) === null || _k === void 0 ? void 0 : _k.PhysicalResourceId) || '',
], ],
}, },
}, },
}, undefined).promise(); }, undefined).promise();
core.info('Build job is starting'); core.info('Build job is starting');
try { try {
yield ECS.waitFor('tasksRunning', { tasks: [((_l = task.tasks) === null || _l === void 0 ? void 0 : _l[0].taskArn) || ""], cluster: clusterName, }).promise(); yield ECS.waitFor('tasksRunning', { tasks: [((_l = task.tasks) === null || _l === void 0 ? void 0 : _l[0].taskArn) || ''], cluster: clusterName }).promise();
} }
catch (error) { catch (error) {
yield new Promise((resolve) => setTimeout(resolve, 3000)); yield new Promise((resolve) => setTimeout(resolve, 3000));
let describeTasks = yield ECS.describeTasks({ let describeTasks = yield ECS.describeTasks({
tasks: [((_m = task.tasks) === null || _m === void 0 ? void 0 : _m[0].taskArn) || ""], tasks: [((_m = task.tasks) === null || _m === void 0 ? void 0 : _m[0].taskArn) || ''],
cluster: clusterName, cluster: clusterName,
}).promise(); }).promise();
core.info(`Build job has ended ${(_p = (_o = describeTasks.tasks) === null || _o === void 0 ? void 0 : _o[0].containers) === null || _p === void 0 ? void 0 : _p[0].lastStatus}`); core.info(`Build job has ended ${(_p = (_o = describeTasks.tasks) === null || _o === void 0 ? void 0 : _o[0].containers) === null || _p === void 0 ? void 0 : _p[0].lastStatus}`);
@ -523,20 +523,23 @@ class AWS {
var _w, _x; var _w, _x;
const tasks = yield ECS.describeTasks({ const tasks = yield ECS.describeTasks({
cluster: clusterName, cluster: clusterName,
tasks: [((_w = task.tasks) === null || _w === void 0 ? void 0 : _w[0].taskArn) || ""], tasks: [((_w = task.tasks) === null || _w === void 0 ? void 0 : _w[0].taskArn) || ''],
}).promise(); }).promise();
return (_x = tasks.tasks) === null || _x === void 0 ? void 0 : _x[0].lastStatus; return (_x = tasks.tasks) === null || _x === void 0 ? void 0 : _x[0].lastStatus;
}); });
const stream = yield kinesis.describeStream({ const stream = yield kinesis
StreamName: ((_r = (_q = taskDefResources.StackResources) === null || _q === void 0 ? void 0 : _q.find((x) => x.LogicalResourceId === 'KinesisStream')) === null || _r === void 0 ? void 0 : _r.PhysicalResourceId) || "", .describeStream({
}, undefined).promise(); StreamName: ((_r = (_q = taskDefResources.StackResources) === null || _q === void 0 ? void 0 : _q.find((x) => x.LogicalResourceId === 'KinesisStream')) === null || _r === void 0 ? void 0 : _r.PhysicalResourceId) ||
'',
}, undefined)
.promise();
let iterator = (yield kinesis let iterator = (yield kinesis
.getShardIterator({ .getShardIterator({
ShardIteratorType: 'TRIM_HORIZON', ShardIteratorType: 'TRIM_HORIZON',
StreamName: stream.StreamDescription.StreamName, StreamName: stream.StreamDescription.StreamName,
ShardId: stream.StreamDescription.Shards[0].ShardId, ShardId: stream.StreamDescription.Shards[0].ShardId,
}) })
.promise()).ShardIterator || ""; .promise()).ShardIterator || '';
yield CF.waitFor('stackCreateComplete', { StackName: taskDefStackNameTTL }).promise(); yield CF.waitFor('stackCreateComplete', { StackName: taskDefStackNameTTL }).promise();
core.info(`Task status is ${yield getTaskStatus()}`); core.info(`Task status is ${yield getTaskStatus()}`);
const logBaseUrl = `https://console.aws.amazon.com/cloudwatch/home?region=${SDK.config.region}#logsV2:log-groups/${taskDefStackName}`; const logBaseUrl = `https://console.aws.amazon.com/cloudwatch/home?region=${SDK.config.region}#logsV2:log-groups/${taskDefStackName}`;
@ -553,7 +556,7 @@ class AWS {
ShardIterator: iterator, ShardIterator: iterator,
}) })
.promise(); .promise();
iterator = records.NextShardIterator || ""; iterator = records.NextShardIterator || '';
if (records.Records.length > 0) { if (records.Records.length > 0) {
for (let index = 0; index < records.Records.length; index++) { for (let index = 0; index < records.Records.length; index++) {
const json = JSON.parse(zlib.gunzipSync(Buffer.from(records.Records[index].Data, 'base64')).toString('utf8')); const json = JSON.parse(zlib.gunzipSync(Buffer.from(records.Records[index].Data, 'base64')).toString('utf8'));
@ -565,9 +568,9 @@ class AWS {
} }
} }
} }
yield ECS.waitFor('tasksStopped', { cluster: clusterName, tasks: [((_s = task.tasks) === null || _s === void 0 ? void 0 : _s[0].taskArn) || ""] }).promise(); yield ECS.waitFor('tasksStopped', { cluster: clusterName, tasks: [((_s = task.tasks) === null || _s === void 0 ? void 0 : _s[0].taskArn) || ''] }).promise();
const exitCode = (_v = (_u = (yield ECS.describeTasks({ const exitCode = (_v = (_u = (yield ECS.describeTasks({
tasks: [((_t = task.tasks) === null || _t === void 0 ? void 0 : _t[0].taskArn) || ""], tasks: [((_t = task.tasks) === null || _t === void 0 ? void 0 : _t[0].taskArn) || ''],
cluster: clusterName, cluster: clusterName,
}).promise()).tasks) === null || _u === void 0 ? void 0 : _u[0].containers) === null || _v === void 0 ? void 0 : _v[0].exitCode; }).promise()).tasks) === null || _u === void 0 ? void 0 : _u[0].containers) === null || _v === void 0 ? void 0 : _v[0].exitCode;
if (exitCode != 0) { if (exitCode != 0) {
@ -583,10 +586,10 @@ class AWS {
StackName: taskDefStackNameTTL, StackName: taskDefStackNameTTL,
}).promise(); }).promise();
yield CF.waitFor('stackDeleteComplete', { yield CF.waitFor('stackDeleteComplete', {
StackName: taskDefStackName StackName: taskDefStackName,
}).promise(); }).promise();
yield CF.waitFor('stackDeleteComplete', { yield CF.waitFor('stackDeleteComplete', {
StackName: taskDefStackNameTTL StackName: taskDefStackNameTTL,
}).promise(); }).promise();
core.info('Cleanup complete'); core.info('Cleanup complete');
}); });

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -9,16 +9,16 @@ import BuildParameters from './build-parameters';
class AWS { class AWS {
static async runBuildJob(buildParameters, baseImage) { static async runBuildJob(buildParameters, baseImage) {
try{ try {
let buildUid = nanoid();
let buildUid = nanoid(); await this.run(
await this.run(buildUid, buildUid,
buildParameters.awsStackName, buildParameters.awsStackName,
'alpine/git', 'alpine/git',
['/bin/sh'], ['/bin/sh'],
[ [
'-c', '-c',
`apk update; `apk update;
apk add git-lfs; apk add git-lfs;
apk add jq; apk add jq;
ls; ls;
@ -26,27 +26,31 @@ class AWS {
git clone https://$GITHUB_TOKEN@github.com/webbertakken/unity-builder.git ${buildUid}/builder; git clone https://$GITHUB_TOKEN@github.com/webbertakken/unity-builder.git ${buildUid}/builder;
cd ${buildUid}/repo; cd ${buildUid}/repo;
git checkout $GITHUB_SHA; git checkout $GITHUB_SHA;
`], `,
'/data', ],
'/data/', '/data',
[ '/data/',
{ [
name: 'GITHUB_SHA', {
value: process.env.GITHUB_SHA, name: 'GITHUB_SHA',
}, value: process.env.GITHUB_SHA,
], },
[ ],
{ [
ParameterKey: 'GithubToken', {
ParameterValue: buildParameters.githubToken, ParameterKey: 'GithubToken',
}, ParameterValue: buildParameters.githubToken,
], },
); ],
await this.run(buildUid, );
buildParameters.awsStackName, await this.run(
baseImage.toString(), buildUid,
['/bin/sh'], buildParameters.awsStackName,
['-c', ` baseImage.toString(),
['/bin/sh'],
[
'-c',
`
cp -r /data/${buildUid}/builder/action/default-build-script /UnityBuilderAction; cp -r /data/${buildUid}/builder/action/default-build-script /UnityBuilderAction;
cp -r /data/${buildUid}/builder/action/entrypoint.sh /entrypoint.sh; cp -r /data/${buildUid}/builder/action/entrypoint.sh /entrypoint.sh;
cp -r /data/${buildUid}/builder/action/steps /steps; cp -r /data/${buildUid}/builder/action/steps /steps;
@ -55,171 +59,182 @@ class AWS {
chmod -R +x /steps; chmod -R +x /steps;
/entrypoint.sh; /entrypoint.sh;
ls ls
`], `,
'/data', ],
`/data/${buildUid}/repo/`, '/data',
[ `/data/${buildUid}/repo/`,
{ [
name: 'GITHUB_WORKSPACE', {
value: `/data/${buildUid}/repo/`, name: 'GITHUB_WORKSPACE',
}, value: `/data/${buildUid}/repo/`,
{ },
name: 'PROJECT_PATH', {
value: buildParameters.projectPath, name: 'PROJECT_PATH',
}, value: buildParameters.projectPath,
{ },
name: 'BUILD_PATH', {
value: buildParameters.buildPath, name: 'BUILD_PATH',
}, value: buildParameters.buildPath,
{ },
name: 'BUILD_FILE', {
value: buildParameters.buildFile, name: 'BUILD_FILE',
}, value: buildParameters.buildFile,
{ },
name: 'BUILD_NAME', {
value: buildParameters.buildName, name: 'BUILD_NAME',
}, value: buildParameters.buildName,
{ },
name: 'BUILD_METHOD', {
value: buildParameters.buildMethod, name: 'BUILD_METHOD',
}, value: buildParameters.buildMethod,
{ },
name: 'CUSTOM_PARAMETERS', {
value: buildParameters.customParameters, name: 'CUSTOM_PARAMETERS',
}, value: buildParameters.customParameters,
{ },
name: 'BUILD_TARGET', {
value: buildParameters.platform, name: 'BUILD_TARGET',
}, value: buildParameters.platform,
{ },
name: 'ANDROID_VERSION_CODE', {
value: buildParameters.androidVersionCode.toString(), name: 'ANDROID_VERSION_CODE',
}, value: buildParameters.androidVersionCode.toString(),
{ },
name: 'ANDROID_KEYSTORE_NAME', {
value: buildParameters.androidKeystoreName, name: 'ANDROID_KEYSTORE_NAME',
}, value: buildParameters.androidKeystoreName,
{ },
name: 'ANDROID_KEYALIAS_NAME', {
value: buildParameters.androidKeyaliasName, name: 'ANDROID_KEYALIAS_NAME',
}, value: buildParameters.androidKeyaliasName,
], },
[ ],
{ [
ParameterKey: 'GithubToken', {
ParameterValue: buildParameters.githubToken, ParameterKey: 'GithubToken',
}, ParameterValue: buildParameters.githubToken,
{ },
ParameterKey: 'UnityLicense', {
ParameterValue: process.env.UNITY_LICENSE?process.env.UNITY_LICENSE:'0' 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: 'UnityEmail',
}, ParameterValue: process.env.UNITY_EMAIL ? process.env.UNITY_EMAIL : '0',
{ },
ParameterKey: 'UnityPassword', {
ParameterValue: process.env.UNITY_PASSWORD?process.env.UNITY_PASSWORD:'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: 'UnitySerial',
}, ParameterValue: process.env.UNITY_SERIAL ? process.env.UNITY_SERIAL : '0',
{ },
ParameterKey: 'AndroidKeystoreBase64', {
ParameterValue: buildParameters.androidKeystoreBase64?buildParameters.androidKeystoreBase64:'0' ParameterKey: 'AndroidKeystoreBase64',
}, ParameterValue: buildParameters.androidKeystoreBase64 ? buildParameters.androidKeystoreBase64 : '0',
{ },
ParameterKey: 'AndroidKeystorePass', {
ParameterValue: buildParameters.androidKeystorePass?buildParameters.androidKeystorePass:'0' ParameterKey: 'AndroidKeystorePass',
}, ParameterValue: buildParameters.androidKeystorePass ? buildParameters.androidKeystorePass : '0',
{ },
ParameterKey: 'AndroidKeyAliasPass', {
ParameterValue: buildParameters.androidKeyaliasPass?buildParameters.androidKeyaliasPass:'0' ParameterKey: 'AndroidKeyAliasPass',
}, ParameterValue: buildParameters.androidKeyaliasPass ? buildParameters.androidKeyaliasPass : '0',
] },
); ],
// Cleanup );
await this.run(buildUid, // Cleanup
buildParameters.awsStackName, await this.run(
'alpine', buildUid,
['/bin/sh'], buildParameters.awsStackName,
[ 'alpine',
'-c', ['/bin/sh'],
` [
'-c',
`
apk update; apk update;
apk add zip apk add zip
zip -r ./${buildUid}/output.zip ./${buildUid}/repo/build zip -r ./${buildUid}/output.zip ./${buildUid}/repo/build
ls ls
`], `,
'/data', ],
'/data/', '/data',
[ '/data/',
{ [
name: 'GITHUB_SHA', {
value: process.env.GITHUB_SHA, name: 'GITHUB_SHA',
}, value: process.env.GITHUB_SHA,
], },
[ ],
{ [
ParameterKey: 'GithubToken', {
ParameterValue: buildParameters.githubToken, ParameterKey: 'GithubToken',
}, ParameterValue: buildParameters.githubToken,
], },
); ],
await this.run(buildUid, );
buildParameters.awsStackName, await this.run(
'amazon/aws-cli', buildUid,
['/bin/sh'], buildParameters.awsStackName,
[ 'amazon/aws-cli',
'-c', ['/bin/sh'],
` [
'-c',
`
aws s3 cp ./${buildUid}/output.zip s3://game-ci-storage/${buildUid} aws s3 cp ./${buildUid}/output.zip s3://game-ci-storage/${buildUid}
rm -r ${buildUid} rm -r ${buildUid}
ls ls
`], `,
'/data', ],
'/data/', '/data',
[ '/data/',
{ [
name: 'GITHUB_SHA', {
value: process.env.GITHUB_SHA, name: 'GITHUB_SHA',
}, value: process.env.GITHUB_SHA,
{ },
name: 'AWS_DEFAULT_REGION', {
value: process.env.AWS_DEFAULT_REGION, name: 'AWS_DEFAULT_REGION',
}, value: process.env.AWS_DEFAULT_REGION,
},
], ],
[ [
{ {
ParameterKey: 'GithubToken', ParameterKey: 'GithubToken',
ParameterValue: buildParameters.githubToken, ParameterValue: buildParameters.githubToken,
}, },
{ {
ParameterKey: 'AWSAccessKeyID', ParameterKey: 'AWSAccessKeyID',
ParameterValue: process.env.AWS_ACCESS_KEY_ID, ParameterValue: process.env.AWS_ACCESS_KEY_ID,
}, },
{ {
ParameterKey: 'AWSSecretAccessKey', ParameterKey: 'AWSSecretAccessKey',
ParameterValue: process.env.AWS_SECRET_ACCESS_KEY, ParameterValue: process.env.AWS_SECRET_ACCESS_KEY,
}, },
], ],
); );
} } catch (error) {
catch(error){
core.setFailed(error); core.setFailed(error);
core.error(error); core.error(error);
} }
} }
static async run(buildUid:string, stackName:string, image:string, entrypoint:string[], commands, mountdir, workingdir, environment, secrets) { static async run(
buildUid: string,
stackName: string,
image: string,
entrypoint: string[],
commands,
mountdir,
workingdir,
environment,
secrets,
) {
const ECS = new SDK.ECS(); const ECS = new SDK.ECS();
const CF = new SDK.CloudFormation(); const CF = new SDK.CloudFormation();
const taskDefStackName = `${stackName}-taskDef-${image}-${buildUid}` const taskDefStackName = `${stackName}-taskDef-${image}-${buildUid}`.toString().replace(/[^\da-z]/gi, '');
.toString()
.replace(/[^\da-z]/gi, '');
const taskDefCloudFormation = fs.readFileSync(`${__dirname}/task-def-formation.yml`, 'utf8'); const taskDefCloudFormation = fs.readFileSync(`${__dirname}/task-def-formation.yml`, 'utf8');
await CF.createStack({ await CF.createStack({
StackName: taskDefStackName, StackName: taskDefStackName,
@ -252,17 +267,17 @@ class AWS {
{ {
ParameterKey: 'BUILDID', ParameterKey: 'BUILDID',
ParameterValue: buildUid, ParameterValue: buildUid,
} },
].concat(secrets), ].concat(secrets),
}).promise(); }).promise();
core.info("Creating build cluster..."); core.info('Creating build cluster...');
const taskDefStackNameTTL = taskDefStackName+"-ttl"; const taskDefStackNameTTL = taskDefStackName + '-ttl';
const ttlCloudFormation = fs.readFileSync(`${__dirname}/cloudformation-stack-ttl.yml`, 'utf8'); const ttlCloudFormation = fs.readFileSync(`${__dirname}/cloudformation-stack-ttl.yml`, 'utf8');
await CF.createStack({ await CF.createStack({
StackName: taskDefStackNameTTL, StackName: taskDefStackNameTTL,
TemplateBody: ttlCloudFormation, TemplateBody: ttlCloudFormation,
Capabilities: [ "CAPABILITY_IAM" ], Capabilities: ['CAPABILITY_IAM'],
Parameters: [ Parameters: [
{ {
ParameterKey: 'StackName', ParameterKey: 'StackName',
@ -270,83 +285,80 @@ class AWS {
}, },
{ {
ParameterKey: 'TTL', ParameterKey: 'TTL',
ParameterValue: "100", ParameterValue: '100',
}, },
{ {
ParameterKey: 'BUILDID', ParameterKey: 'BUILDID',
ParameterValue: buildUid, ParameterValue: buildUid,
} },
], ],
}).promise(); }).promise();
core.info("Creating cleanup cluster..."); core.info('Creating cleanup cluster...');
try{ try {
await CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise(); await CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise();
}catch(error){ } catch (error) {
core.error(error); core.error(error);
} }
core.info("Cloud formation stack created"); core.info('Cloud formation stack created');
const taskDefResources = await CF.describeStackResources({ const taskDefResources = await CF.describeStackResources({
StackName: taskDefStackName, StackName: taskDefStackName,
}).promise(); }).promise();
const baseResources = await CF.describeStackResources({ StackName: stackName }).promise(); const baseResources = await CF.describeStackResources({ StackName: stackName }).promise();
const clusterName = baseResources.StackResources?.find( const clusterName =
(x) => x.LogicalResourceId === 'ECSCluster', baseResources.StackResources?.find((x) => x.LogicalResourceId === 'ECSCluster')?.PhysicalResourceId || '';
)?.PhysicalResourceId || ""; const task = await ECS.runTask(
const task = await ECS.runTask({ {
cluster: clusterName, cluster: clusterName,
taskDefinition: taskDefResources.StackResources?.find( taskDefinition:
(x) => x.LogicalResourceId === 'TaskDefinition', taskDefResources.StackResources?.find((x) => x.LogicalResourceId === 'TaskDefinition')?.PhysicalResourceId ||
)?.PhysicalResourceId || "", '',
platformVersion: '1.4.0', platformVersion: '1.4.0',
overrides: { overrides: {
containerOverrides: [ containerOverrides: [
{ {
name: taskDefStackName, name: taskDefStackName,
environment: environment.concat([ environment: environment.concat([{ name: 'BUILDID', value: buildUid }]),
{name:'BUILDID', value: buildUid} },
]),
},
],
},
launchType: 'FARGATE',
networkConfiguration: {
awsvpcConfiguration: {
subnets: [
baseResources.StackResources?.find((x) => x.LogicalResourceId === 'PublicSubnetOne')?.PhysicalResourceId || "",
baseResources.StackResources?.find((x) => x.LogicalResourceId === 'PublicSubnetTwo')?.PhysicalResourceId || "",
],
assignPublicIp: 'ENABLED',
securityGroups: [
baseResources.StackResources?.find((x) => x.LogicalResourceId === 'ContainerSecurityGroup')?.PhysicalResourceId || "",
], ],
}, },
launchType: 'FARGATE',
networkConfiguration: {
awsvpcConfiguration: {
subnets: [
baseResources.StackResources?.find((x) => x.LogicalResourceId === 'PublicSubnetOne')
?.PhysicalResourceId || '',
baseResources.StackResources?.find((x) => x.LogicalResourceId === 'PublicSubnetTwo')
?.PhysicalResourceId || '',
],
assignPublicIp: 'ENABLED',
securityGroups: [
baseResources.StackResources?.find((x) => x.LogicalResourceId === 'ContainerSecurityGroup')
?.PhysicalResourceId || '',
],
},
},
}, },
}, undefined).promise(); undefined,
).promise();
core.info('Build job is starting'); core.info('Build job is starting');
try { try {
await ECS.waitFor('tasksRunning', {tasks: [task.tasks?.[0].taskArn||""], await ECS.waitFor('tasksRunning', { tasks: [task.tasks?.[0].taskArn || ''], cluster: clusterName }).promise();
cluster: clusterName,
}).promise();
} catch (error) { } catch (error) {
await new Promise((resolve) => setTimeout(resolve, 3000)); await new Promise((resolve) => setTimeout(resolve, 3000));
let describeTasks = await ECS.describeTasks({ let describeTasks = await ECS.describeTasks({
tasks: [task.tasks?.[0].taskArn||""], tasks: [task.tasks?.[0].taskArn || ''],
cluster: clusterName, cluster: clusterName,
}).promise(); }).promise();
core.info( core.info(`Build job has ended ${describeTasks.tasks?.[0].containers?.[0].lastStatus}`);
`Build job has ended ${describeTasks.tasks?.[0].containers?.[0].lastStatus}`
);
core.setFailed(error); core.setFailed(error);
core.error(error); core.error(error);
} }
core.info(`Build job is running`); core.info(`Build job is running`);
@ -356,29 +368,35 @@ class AWS {
const getTaskStatus = async () => { const getTaskStatus = async () => {
const tasks = await ECS.describeTasks({ const tasks = await ECS.describeTasks({
cluster: clusterName, cluster: clusterName,
tasks: [task.tasks?.[0].taskArn||""], tasks: [task.tasks?.[0].taskArn || ''],
}).promise(); }).promise();
return tasks.tasks?.[0].lastStatus; return tasks.tasks?.[0].lastStatus;
}; };
const stream = await kinesis.describeStream({ const stream = await kinesis
StreamName: taskDefResources.StackResources?.find( .describeStream(
(x) => x.LogicalResourceId === 'KinesisStream', {
)?.PhysicalResourceId||"", StreamName:
}, undefined).promise(); taskDefResources.StackResources?.find((x) => x.LogicalResourceId === 'KinesisStream')?.PhysicalResourceId ||
'',
},
undefined,
)
.promise();
let iterator = ( let iterator =
await kinesis (
.getShardIterator({ await kinesis
ShardIteratorType: 'TRIM_HORIZON', .getShardIterator({
StreamName: stream.StreamDescription.StreamName, ShardIteratorType: 'TRIM_HORIZON',
ShardId: stream.StreamDescription.Shards[0].ShardId, StreamName: stream.StreamDescription.StreamName,
}) ShardId: stream.StreamDescription.Shards[0].ShardId,
.promise() })
).ShardIterator||""; .promise()
).ShardIterator || '';
await CF.waitFor('stackCreateComplete', { StackName: taskDefStackNameTTL }).promise(); await CF.waitFor('stackCreateComplete', { StackName: taskDefStackNameTTL }).promise();
core.info(`Task status is ${await getTaskStatus()}`); core.info(`Task status is ${await getTaskStatus()}`);
const logBaseUrl = `https://console.aws.amazon.com/cloudwatch/home?region=${SDK.config.region}#logsV2:log-groups/${taskDefStackName}`; const logBaseUrl = `https://console.aws.amazon.com/cloudwatch/home?region=${SDK.config.region}#logsV2:log-groups/${taskDefStackName}`;
@ -396,11 +414,11 @@ class AWS {
ShardIterator: iterator, ShardIterator: iterator,
}) })
.promise(); .promise();
iterator = records.NextShardIterator||""; iterator = records.NextShardIterator || '';
if (records.Records.length > 0) { if (records.Records.length > 0) {
for (let index = 0; index < records.Records.length; index++) { for (let index = 0; index < records.Records.length; index++) {
const json = JSON.parse( const json = JSON.parse(
zlib.gunzipSync(Buffer.from((records.Records[index].Data as string), 'base64')).toString('utf8'), zlib.gunzipSync(Buffer.from(records.Records[index].Data as string, 'base64')).toString('utf8'),
); );
if (json.messageType === 'DATA_MESSAGE') { if (json.messageType === 'DATA_MESSAGE') {
for (let logEventsIndex = 0; logEventsIndex < json.logEvents.length; logEventsIndex++) { for (let logEventsIndex = 0; logEventsIndex < json.logEvents.length; logEventsIndex++) {
@ -411,18 +429,18 @@ class AWS {
} }
} }
await ECS.waitFor('tasksStopped', { cluster: clusterName, tasks: [task.tasks?.[0].taskArn||""]}).promise(); await ECS.waitFor('tasksStopped', { cluster: clusterName, tasks: [task.tasks?.[0].taskArn || ''] }).promise();
const exitCode = (await ECS.describeTasks({ const exitCode = (
tasks: [task.tasks?.[0].taskArn||""], await ECS.describeTasks({
tasks: [task.tasks?.[0].taskArn || ''],
cluster: clusterName, cluster: clusterName,
}).promise() }).promise()
).tasks?.[0].containers?.[0].exitCode; ).tasks?.[0].containers?.[0].exitCode;
if(exitCode!=0){ if (exitCode != 0) {
core.error(`job finished with exit code ${exitCode}`) core.error(`job finished with exit code ${exitCode}`);
} } else {
else{
core.info(`Build job has finished with exit code 0`); core.info(`Build job has finished with exit code 0`);
} }
@ -435,11 +453,11 @@ class AWS {
}).promise(); }).promise();
await CF.waitFor('stackDeleteComplete', { await CF.waitFor('stackDeleteComplete', {
StackName: taskDefStackName StackName: taskDefStackName,
}).promise(); }).promise();
await CF.waitFor('stackDeleteComplete', { await CF.waitFor('stackDeleteComplete', {
StackName: taskDefStackNameTTL StackName: taskDefStackNameTTL,
}).promise(); }).promise();
core.info('Cleanup complete'); core.info('Cleanup complete');
@ -451,4 +469,4 @@ class AWS {
}); });
} }
} }
export default AWS; export default AWS;

View File

@ -34,7 +34,7 @@ class BuildParameters {
androidKeyaliasPass: Input.androidKeyaliasPass, androidKeyaliasPass: Input.androidKeyaliasPass,
customParameters: Input.customParameters, customParameters: Input.customParameters,
remoteBuildCluster: Input.remoteBuildCluster, remoteBuildCluster: Input.remoteBuildCluster,
awsStackName:Input.awsStackName, awsStackName: Input.awsStackName,
kubeConfig: Input.kubeConfig, kubeConfig: Input.kubeConfig,
githubToken: Input.githubToken, githubToken: Input.githubToken,
kubeContainerMemory: Input.kubeContainerMemory, kubeContainerMemory: Input.kubeContainerMemory,

View File

@ -25,5 +25,5 @@ export {
Unity, Unity,
Versioning, Versioning,
Kubernetes, Kubernetes,
AWS AWS,
}; };

View File

@ -85,11 +85,11 @@ class Input {
return core.getInput('customParameters') || ''; return core.getInput('customParameters') || '';
} }
static get remoteBuildCluster(){ static get remoteBuildCluster() {
return core.getInput('remoteBuildCluster') || ''; return core.getInput('remoteBuildCluster') || '';
} }
static get awsStackName(){ static get awsStackName() {
return core.getInput('awsStackName') || ''; return core.getInput('awsStackName') || '';
} }