tests: assert BuildSucceeded; skip S3 locally; AWS describeTasks backoff; lint/format fixes
parent
eb8b92cda1
commit
c8f881a385
|
@ -1954,7 +1954,11 @@ class AWSTaskRunner {
|
|||
while (exitCode === undefined) {
|
||||
await new Promise((resolve) => resolve(10000));
|
||||
taskData = await AWSTaskRunner.describeTasks(cluster, taskArn);
|
||||
containerState = taskData.containers?.[0];
|
||||
const containers = taskData?.containers;
|
||||
if (!containers || containers.length === 0) {
|
||||
continue;
|
||||
}
|
||||
containerState = containers[0];
|
||||
exitCode = containerState?.exitCode;
|
||||
}
|
||||
cloud_runner_logger_1.default.log(`Container State: ${JSON.stringify(containerState, undefined, 4)}`);
|
||||
|
@ -1981,18 +1985,31 @@ class AWSTaskRunner {
|
|||
catch (error_) {
|
||||
const error = error_;
|
||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||
cloud_runner_logger_1.default.log(`Cloud runner job has ended ${(await AWSTaskRunner.describeTasks(cluster, taskArn)).containers?.[0].lastStatus}`);
|
||||
const taskAfterError = await AWSTaskRunner.describeTasks(cluster, taskArn);
|
||||
cloud_runner_logger_1.default.log(`Cloud runner job has ended ${taskAfterError?.containers?.[0]?.lastStatus}`);
|
||||
core.setFailed(error);
|
||||
core.error(error);
|
||||
}
|
||||
}
|
||||
static async describeTasks(clusterName, taskArn) {
|
||||
const tasks = await AWSTaskRunner.ECS.send(new client_ecs_1.DescribeTasksCommand({ cluster: clusterName, tasks: [taskArn] }));
|
||||
if (tasks.tasks?.[0]) {
|
||||
return tasks.tasks?.[0];
|
||||
}
|
||||
else {
|
||||
throw new Error('No task found');
|
||||
const maxAttempts = 6;
|
||||
let delayMs = 500;
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
try {
|
||||
const tasks = await AWSTaskRunner.ECS.send(new client_ecs_1.DescribeTasksCommand({ cluster: clusterName, tasks: [taskArn] }));
|
||||
if (tasks.tasks?.[0]) {
|
||||
return tasks.tasks?.[0];
|
||||
}
|
||||
throw new Error('No task found');
|
||||
}
|
||||
catch (error) {
|
||||
const isThrottle = error?.name === 'ThrottlingException' || /rate exceeded/i.test(String(error?.message));
|
||||
if (!isThrottle || attempt === maxAttempts) {
|
||||
throw error;
|
||||
}
|
||||
await new Promise((r) => setTimeout(r, delayMs));
|
||||
delayMs *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
static async streamLogsUntilTaskStops(clusterName, taskArn, kinesisStreamName) {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,19 +1,5 @@
|
|||
import {
|
||||
DescribeTasksCommand,
|
||||
ECS,
|
||||
RunTaskCommand,
|
||||
RunTaskCommandInput,
|
||||
Task,
|
||||
waitUntilTasksRunning,
|
||||
} from '@aws-sdk/client-ecs';
|
||||
import {
|
||||
DescribeStreamCommand,
|
||||
DescribeStreamCommandOutput,
|
||||
GetRecordsCommand,
|
||||
GetRecordsCommandOutput,
|
||||
GetShardIteratorCommand,
|
||||
Kinesis,
|
||||
} from '@aws-sdk/client-kinesis';
|
||||
import { DescribeTasksCommand, ECS, RunTaskCommand, waitUntilTasksRunning } from '@aws-sdk/client-ecs';
|
||||
import { DescribeStreamCommand, GetRecordsCommand, GetShardIteratorCommand, Kinesis } from '@aws-sdk/client-kinesis';
|
||||
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
||||
import * as core from '@actions/core';
|
||||
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
||||
|
@ -75,7 +61,7 @@ class AWSTaskRunner {
|
|||
throw new Error(`Container Overrides length must be at most 8192`);
|
||||
}
|
||||
|
||||
const task = await AWSTaskRunner.ECS.send(new RunTaskCommand(runParameters as RunTaskCommandInput));
|
||||
const task = await AWSTaskRunner.ECS.send(new RunTaskCommand(runParameters as any));
|
||||
const taskArn = task.tasks?.[0].taskArn || '';
|
||||
CloudRunnerLogger.log('Cloud runner job is starting');
|
||||
await AWSTaskRunner.waitUntilTaskRunning(taskArn, cluster);
|
||||
|
@ -100,7 +86,11 @@ class AWSTaskRunner {
|
|||
while (exitCode === undefined) {
|
||||
await new Promise((resolve) => resolve(10000));
|
||||
taskData = await AWSTaskRunner.describeTasks(cluster, taskArn);
|
||||
containerState = taskData.containers?.[0];
|
||||
const containers = taskData?.containers as any[] | undefined;
|
||||
if (!containers || containers.length === 0) {
|
||||
continue;
|
||||
}
|
||||
containerState = containers[0];
|
||||
exitCode = containerState?.exitCode;
|
||||
}
|
||||
CloudRunnerLogger.log(`Container State: ${JSON.stringify(containerState, undefined, 4)}`);
|
||||
|
@ -133,11 +123,8 @@ class AWSTaskRunner {
|
|||
} catch (error_) {
|
||||
const error = error_ as Error;
|
||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||
CloudRunnerLogger.log(
|
||||
`Cloud runner job has ended ${
|
||||
(await AWSTaskRunner.describeTasks(cluster, taskArn)).containers?.[0].lastStatus
|
||||
}`,
|
||||
);
|
||||
const taskAfterError = await AWSTaskRunner.describeTasks(cluster, taskArn);
|
||||
CloudRunnerLogger.log(`Cloud runner job has ended ${taskAfterError?.containers?.[0]?.lastStatus}`);
|
||||
|
||||
core.setFailed(error);
|
||||
core.error(error);
|
||||
|
@ -145,11 +132,25 @@ class AWSTaskRunner {
|
|||
}
|
||||
|
||||
static async describeTasks(clusterName: string, taskArn: string) {
|
||||
const tasks = await AWSTaskRunner.ECS.send(new DescribeTasksCommand({ cluster: clusterName, tasks: [taskArn] }));
|
||||
if (tasks.tasks?.[0]) {
|
||||
return tasks.tasks?.[0];
|
||||
} else {
|
||||
throw new Error('No task found');
|
||||
const maxAttempts = 6;
|
||||
let delayMs = 500;
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
try {
|
||||
const tasks = await AWSTaskRunner.ECS.send(
|
||||
new DescribeTasksCommand({ cluster: clusterName, tasks: [taskArn] }),
|
||||
);
|
||||
if (tasks.tasks?.[0]) {
|
||||
return tasks.tasks?.[0];
|
||||
}
|
||||
throw new Error('No task found');
|
||||
} catch (error: any) {
|
||||
const isThrottle = error?.name === 'ThrottlingException' || /rate exceeded/i.test(String(error?.message));
|
||||
if (!isThrottle || attempt === maxAttempts) {
|
||||
throw error;
|
||||
}
|
||||
await new Promise((r) => setTimeout(r, delayMs));
|
||||
delayMs *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,7 +201,7 @@ class AWSTaskRunner {
|
|||
return { iterator, shouldReadLogs, output, shouldCleanup };
|
||||
}
|
||||
|
||||
private static checkStreamingShouldContinue(taskData: Task, timestamp: number, shouldReadLogs: boolean) {
|
||||
private static checkStreamingShouldContinue(taskData: any, timestamp: number, shouldReadLogs: boolean) {
|
||||
if (taskData?.lastStatus === 'UNKNOWN') {
|
||||
CloudRunnerLogger.log('## Cloud runner job unknwon');
|
||||
}
|
||||
|
@ -220,7 +221,7 @@ class AWSTaskRunner {
|
|||
}
|
||||
|
||||
private static logRecords(
|
||||
records: GetRecordsCommandOutput,
|
||||
records: any,
|
||||
iterator: string,
|
||||
shouldReadLogs: boolean,
|
||||
output: string,
|
||||
|
@ -251,7 +252,7 @@ class AWSTaskRunner {
|
|||
return await AWSTaskRunner.Kinesis.send(new DescribeStreamCommand({ StreamName: kinesisStreamName }));
|
||||
}
|
||||
|
||||
private static async getLogIterator(stream: DescribeStreamCommandOutput) {
|
||||
private static async getLogIterator(stream: any) {
|
||||
return (
|
||||
(
|
||||
await AWSTaskRunner.Kinesis.send(
|
||||
|
|
|
@ -54,21 +54,8 @@ describe('Cloud Runner pre-built S3 steps', () => {
|
|||
const buildParameter2 = await CreateParameters(overrides);
|
||||
const baseImage2 = new ImageTag(buildParameter2);
|
||||
const results2Object = await CloudRunner.run(buildParameter2, baseImage2.toString());
|
||||
const results2 = results2Object.BuildResults;
|
||||
CloudRunnerLogger.log(`run 2 succeeded`);
|
||||
|
||||
// Look for multiple indicators of a successful build
|
||||
const buildIndicators = [
|
||||
'Build succeeded',
|
||||
'Build succeeded!',
|
||||
'Build Succeeded',
|
||||
'succeeded',
|
||||
'Cloud Runner finished running standard build automation',
|
||||
'Cloud runner job has finished successfully',
|
||||
];
|
||||
|
||||
const buildWasSuccessful = buildIndicators.some((indicator) => results2.includes(indicator));
|
||||
expect(buildWasSuccessful).toBeTruthy();
|
||||
expect(results2Object.BuildSucceeded).toBe(true);
|
||||
|
||||
// Only run S3 operations if we're in CI or AWS CLI is available
|
||||
if (isCI || awsAvailable) {
|
||||
|
|
|
@ -44,10 +44,10 @@ describe('Cloud Runner Caching', () => {
|
|||
const results = resultsObject.BuildResults;
|
||||
const libraryString = 'Rebuilding Library because the asset database could not be found!';
|
||||
const cachePushFail = 'Did not push source folder to cache because it was empty Library';
|
||||
const buildSucceededString = 'Build succeeded';
|
||||
|
||||
expect(results).toContain(libraryString);
|
||||
expect(results).toContain(buildSucceededString);
|
||||
expect(resultsObject.BuildSucceeded).toBe(true);
|
||||
|
||||
// Keep minimal assertions to reduce brittleness
|
||||
expect(results).not.toContain(cachePushFail);
|
||||
|
||||
CloudRunnerLogger.log(`run 1 succeeded`);
|
||||
|
@ -72,7 +72,6 @@ describe('Cloud Runner Caching', () => {
|
|||
CloudRunnerLogger.log(`run 2 succeeded`);
|
||||
|
||||
const build2ContainsCacheKey = results2.includes(buildParameter.cacheKey);
|
||||
const build2ContainsBuildSucceeded = results2.includes(buildSucceededString);
|
||||
const build2NotContainsZeroLibraryCacheFilesMessage = !results2.includes(
|
||||
'There is 0 files/dir in the cache pulled contents for Library',
|
||||
);
|
||||
|
@ -82,8 +81,7 @@ describe('Cloud Runner Caching', () => {
|
|||
|
||||
expect(build2ContainsCacheKey).toBeTruthy();
|
||||
expect(results2).toContain('Activation successful');
|
||||
expect(build2ContainsBuildSucceeded).toBeTruthy();
|
||||
expect(results2).toContain(buildSucceededString);
|
||||
expect(results2Object.BuildSucceeded).toBe(true);
|
||||
const splitResults = results2.split('Activation successful');
|
||||
expect(splitResults[splitResults.length - 1]).not.toContain(libraryString);
|
||||
expect(build2NotContainsZeroLibraryCacheFilesMessage).toBeTruthy();
|
||||
|
|
|
@ -34,10 +34,10 @@ describe('Cloud Runner Retain Workspace', () => {
|
|||
const results = resultsObject.BuildResults;
|
||||
const libraryString = 'Rebuilding Library because the asset database could not be found!';
|
||||
const cachePushFail = 'Did not push source folder to cache because it was empty Library';
|
||||
const buildSucceededString = 'Build succeeded';
|
||||
|
||||
expect(results).toContain(libraryString);
|
||||
expect(results).toContain(buildSucceededString);
|
||||
expect(resultsObject.BuildSucceeded).toBe(true);
|
||||
|
||||
// Keep minimal assertions to reduce brittleness
|
||||
expect(results).not.toContain(cachePushFail);
|
||||
|
||||
if (CloudRunnerOptions.providerStrategy === `local-docker`) {
|
||||
|
@ -61,7 +61,6 @@ describe('Cloud Runner Retain Workspace', () => {
|
|||
const build2ContainsBuildGuid1FromRetainedWorkspace = results2.includes(buildParameter.buildGuid);
|
||||
const build2ContainsRetainedWorkspacePhrase = results2.includes(`Retained Workspace:`);
|
||||
const build2ContainsWorkspaceExistsAlreadyPhrase = results2.includes(`Retained Workspace Already Exists!`);
|
||||
const build2ContainsBuildSucceeded = results2.includes(buildSucceededString);
|
||||
const build2NotContainsZeroLibraryCacheFilesMessage = !results2.includes(
|
||||
'There is 0 files/dir in the cache pulled contents for Library',
|
||||
);
|
||||
|
@ -73,7 +72,7 @@ describe('Cloud Runner Retain Workspace', () => {
|
|||
expect(build2ContainsRetainedWorkspacePhrase).toBeTruthy();
|
||||
expect(build2ContainsWorkspaceExistsAlreadyPhrase).toBeTruthy();
|
||||
expect(build2ContainsBuildGuid1FromRetainedWorkspace).toBeTruthy();
|
||||
expect(build2ContainsBuildSucceeded).toBeTruthy();
|
||||
expect(results2Object.BuildSucceeded).toBe(true);
|
||||
expect(build2NotContainsZeroLibraryCacheFilesMessage).toBeTruthy();
|
||||
expect(build2NotContainsZeroLFSCacheFilesMessage).toBeTruthy();
|
||||
const splitResults = results2.split('Activation successful');
|
||||
|
|
Loading…
Reference in New Issue