mirror of
https://github.com/game-ci/unity-builder.git
synced 2026-06-02 06:46:15 -07:00
* Rename "Cloud Runner" to "Orchestrator" across entire codebase Breaking change: All CloudRunner classes, options, environment variables, and action.yml inputs have been renamed to Orchestrator equivalents. - Renamed src/model/cloud-runner/ directory to src/model/orchestrator/ - Renamed all cloud-runner-* files to orchestrator-* - Renamed all CloudRunner* classes to Orchestrator* (15+ classes) - Renamed all cloudRunner* properties to orchestrator* equivalents - Renamed CLOUD_RUNNER_* env vars to ORCHESTRATOR_* - Updated action.yml [CloudRunner] markers to [Orchestrator] - Updated workflow files and package.json test scripts - Updated all runtime strings (cache paths, log messages, branch refs) - Rebuilt dist/index.js No backward compatibility layer is provided. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove tracked log/temp files and add to .gitignore Remove $LOG_FILE and temp/job-log.txt debug artifacts that should not be in the repository. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
171 lines
5.8 KiB
TypeScript
171 lines
5.8 KiB
TypeScript
import OrchestratorLogger from '../../services/core/orchestrator-logger';
|
|
import * as core from '@actions/core';
|
|
import {
|
|
CloudFormation,
|
|
CreateStackCommand,
|
|
// eslint-disable-next-line import/named
|
|
CreateStackCommandInput,
|
|
DescribeStacksCommand,
|
|
// eslint-disable-next-line import/named
|
|
DescribeStacksCommandInput,
|
|
ListStacksCommand,
|
|
// eslint-disable-next-line import/named
|
|
Parameter,
|
|
UpdateStackCommand,
|
|
// eslint-disable-next-line import/named
|
|
UpdateStackCommandInput,
|
|
waitUntilStackCreateComplete,
|
|
waitUntilStackUpdateComplete,
|
|
} from '@aws-sdk/client-cloudformation';
|
|
import { BaseStackFormation } from './cloud-formations/base-stack-formation';
|
|
import crypto from 'node:crypto';
|
|
|
|
const DEFAULT_STACK_WAIT_TIME_SECONDS = 600;
|
|
|
|
function getStackWaitTime(): number {
|
|
const overrideValue = Number(process.env.ORCHESTRATOR_AWS_STACK_WAIT_TIME ?? '');
|
|
if (!Number.isNaN(overrideValue) && overrideValue > 0) {
|
|
return overrideValue;
|
|
}
|
|
|
|
return DEFAULT_STACK_WAIT_TIME_SECONDS;
|
|
}
|
|
|
|
export class AWSBaseStack {
|
|
constructor(baseStackName: string) {
|
|
this.baseStackName = baseStackName;
|
|
}
|
|
private baseStackName: string;
|
|
|
|
async setupBaseStack(CF: CloudFormation) {
|
|
const baseStackName = this.baseStackName;
|
|
const stackWaitTimeSeconds = getStackWaitTime();
|
|
|
|
const baseStack = BaseStackFormation.formation;
|
|
|
|
// Cloud Formation Input
|
|
const describeStackInput: DescribeStacksCommandInput = {
|
|
StackName: baseStackName,
|
|
};
|
|
const parametersWithoutHash: Parameter[] = [{ ParameterKey: 'EnvironmentName', ParameterValue: baseStackName }];
|
|
const parametersHash = crypto
|
|
.createHash('md5')
|
|
.update(baseStack + JSON.stringify(parametersWithoutHash))
|
|
.digest('hex');
|
|
const parameters: Parameter[] = [
|
|
...parametersWithoutHash,
|
|
...[{ ParameterKey: 'Version', ParameterValue: parametersHash }],
|
|
];
|
|
const updateInput: UpdateStackCommandInput = {
|
|
StackName: baseStackName,
|
|
TemplateBody: baseStack,
|
|
Parameters: parameters,
|
|
Capabilities: ['CAPABILITY_IAM'],
|
|
};
|
|
const createStackInput: CreateStackCommandInput = {
|
|
StackName: baseStackName,
|
|
TemplateBody: baseStack,
|
|
Parameters: parameters,
|
|
Capabilities: ['CAPABILITY_IAM'],
|
|
};
|
|
|
|
const stacks = await CF.send(
|
|
new ListStacksCommand({
|
|
StackStatusFilter: [
|
|
'CREATE_IN_PROGRESS',
|
|
'UPDATE_IN_PROGRESS',
|
|
'UPDATE_COMPLETE',
|
|
'CREATE_COMPLETE',
|
|
'ROLLBACK_COMPLETE',
|
|
],
|
|
}),
|
|
);
|
|
const stackNames = stacks.StackSummaries?.map((x) => x.StackName) || [];
|
|
const stackExists: boolean = stackNames.includes(baseStackName);
|
|
const describeStack = async () => {
|
|
return await CF.send(new DescribeStacksCommand(describeStackInput));
|
|
};
|
|
try {
|
|
if (!stackExists) {
|
|
OrchestratorLogger.log(`${baseStackName} stack does not exist (${JSON.stringify(stackNames)})`);
|
|
let created = false;
|
|
try {
|
|
await CF.send(new CreateStackCommand(createStackInput));
|
|
created = true;
|
|
} catch (error: any) {
|
|
const message = `${error?.name ?? ''} ${error?.message ?? ''}`;
|
|
if (message.includes('AlreadyExistsException')) {
|
|
OrchestratorLogger.log(`Base stack already exists, continuing with describe`);
|
|
} else {
|
|
throw error;
|
|
}
|
|
}
|
|
if (created) {
|
|
OrchestratorLogger.log(`created stack (version: ${parametersHash})`);
|
|
}
|
|
}
|
|
const CFState = await describeStack();
|
|
let stack = CFState.Stacks?.[0];
|
|
if (!stack) {
|
|
throw new Error(`Base stack doesn't exist, even after creation, stackExists check: ${stackExists}`);
|
|
}
|
|
const stackVersion = stack.Parameters?.find((x) => x.ParameterKey === 'Version')?.ParameterValue;
|
|
|
|
if (stack.StackStatus === 'CREATE_IN_PROGRESS') {
|
|
OrchestratorLogger.log(
|
|
`Waiting up to ${stackWaitTimeSeconds}s for '${baseStackName}' CloudFormation creation to finish`,
|
|
);
|
|
await waitUntilStackCreateComplete(
|
|
{
|
|
client: CF,
|
|
maxWaitTime: stackWaitTimeSeconds,
|
|
},
|
|
describeStackInput,
|
|
);
|
|
}
|
|
|
|
if (stackExists) {
|
|
OrchestratorLogger.log(`Base stack exists (version: ${stackVersion}, local version: ${parametersHash})`);
|
|
if (parametersHash !== stackVersion) {
|
|
OrchestratorLogger.log(`Attempting update of base stack`);
|
|
try {
|
|
await CF.send(new UpdateStackCommand(updateInput));
|
|
} catch (error: any) {
|
|
if (error['message'].includes('No updates are to be performed')) {
|
|
OrchestratorLogger.log(`No updates are to be performed`);
|
|
} else {
|
|
OrchestratorLogger.log(`Update Failed (Stack name: ${baseStackName})`);
|
|
OrchestratorLogger.log(error['message']);
|
|
}
|
|
OrchestratorLogger.log(`Continuing...`);
|
|
}
|
|
} else {
|
|
OrchestratorLogger.log(`No update required`);
|
|
}
|
|
stack = (await describeStack()).Stacks?.[0];
|
|
if (!stack) {
|
|
throw new Error(
|
|
`Base stack doesn't exist, even after updating and creation, stackExists check: ${stackExists}`,
|
|
);
|
|
}
|
|
if (stack.StackStatus === 'UPDATE_IN_PROGRESS') {
|
|
OrchestratorLogger.log(
|
|
`Waiting up to ${stackWaitTimeSeconds}s for '${baseStackName}' CloudFormation update to finish`,
|
|
);
|
|
await waitUntilStackUpdateComplete(
|
|
{
|
|
client: CF,
|
|
maxWaitTime: stackWaitTimeSeconds,
|
|
},
|
|
describeStackInput,
|
|
);
|
|
}
|
|
}
|
|
OrchestratorLogger.log('base stack is now ready');
|
|
} catch (error) {
|
|
core.error(JSON.stringify(await describeStack(), undefined, 4));
|
|
throw error;
|
|
}
|
|
}
|
|
}
|