mirror of
https://github.com/game-ci/unity-builder.git
synced 2026-06-17 13:36:48 -07:00
triggerWorkflowOnComplete param for cloud runner
This commit is contained in:
@@ -39,20 +39,21 @@ jobs:
|
||||
if: github.event.event_type != 'pull_request_target'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout (default)
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
lfs: false
|
||||
- run: yarn
|
||||
- run: yarn run cli -m checks-update
|
||||
timeout-minutes: 180
|
||||
- timeout-minutes: 180
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
PROJECT_PATH: test-project
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GIT_PRIVATE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TARGET_PLATFORM: StandaloneWindows64
|
||||
cloudRunnerTests: true
|
||||
versioning: None
|
||||
CLOUD_RUNNER_CLUSTER: local-docker
|
||||
AWS_BASE_STACK_NAME: game-ci-github-pipelines
|
||||
CHECKS_UPDATE: ${{ github.event.inputs.checksObject }}
|
||||
run: |
|
||||
git clone -b cloud-runner-develop https://github.com/game-ci/unity-builder
|
||||
cd unity-builder
|
||||
yarn
|
||||
ls
|
||||
yarn run cli -m checks-update
|
||||
|
||||
@@ -31,6 +31,8 @@ env:
|
||||
UNITY_VERSION: 2019.3.15f1
|
||||
USE_IL2CPP: false
|
||||
USE_GKE_GCLOUD_AUTH_PLUGIN: true
|
||||
GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
integrationTests:
|
||||
@@ -49,42 +51,31 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
lfs: false
|
||||
- uses: google-github-actions/auth@v1
|
||||
with:
|
||||
credentials_json: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
|
||||
- name: 'Set up Cloud SDK'
|
||||
uses: 'google-github-actions/setup-gcloud@v1'
|
||||
- name: Get GKE cluster credentials
|
||||
run: |
|
||||
export USE_GKE_GCLOUD_AUTH_PLUGIN=True
|
||||
gcloud components install gke-gcloud-auth-plugin
|
||||
gcloud container clusters get-credentials $GKE_CLUSTER --zone $GKE_ZONE --project $GKE_PROJECT
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: eu-west-2
|
||||
- uses: google-github-actions/auth@v1
|
||||
if: matrix.CloudRunnerCluster == 'k8s'
|
||||
with:
|
||||
credentials_json: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
|
||||
- name: 'Set up Cloud SDK'
|
||||
if: matrix.CloudRunnerCluster == 'k8s'
|
||||
uses: 'google-github-actions/setup-gcloud@v1'
|
||||
- name: Get GKE cluster credentials
|
||||
if: matrix.CloudRunnerCluster == 'k8s'
|
||||
run: |
|
||||
export USE_GKE_GCLOUD_AUTH_PLUGIN=True
|
||||
gcloud components install gke-gcloud-auth-plugin
|
||||
gcloud container clusters get-credentials $GKE_CLUSTER --zone $GKE_ZONE --project $GKE_PROJECT
|
||||
- run: yarn
|
||||
- run: yarn run test "cloud-runner-async-workflow" --detectOpenHandles --forceExit --runInBand
|
||||
if: matrix.CloudRunnerCluster != 'local-docker'
|
||||
timeout-minutes: 180
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
PROJECT_PATH: test-project
|
||||
GIT_PRIVATE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TARGET_PLATFORM: StandaloneWindows64
|
||||
cloudRunnerTests: true
|
||||
versioning: None
|
||||
CLOUD_RUNNER_CLUSTER: ${{ matrix.cloudRunnerCluster }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- run: yarn run test-i --detectOpenHandles --forceExit --runInBand
|
||||
if: matrix.CloudRunnerCluster == 'local-docker'
|
||||
timeout-minutes: 180
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
PROJECT_PATH: test-project
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TARGET_PLATFORM: StandaloneWindows64
|
||||
cloudRunnerTests: true
|
||||
versioning: None
|
||||
@@ -114,14 +105,12 @@ jobs:
|
||||
- run: yarn
|
||||
- uses: ./
|
||||
id: unity-build
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
with:
|
||||
cloudRunnerTests: true
|
||||
versioning: None
|
||||
projectPath: test-project
|
||||
gitPrivateToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
targetPlatform: ${{ matrix.targetPlatform }}
|
||||
cloudRunnerCluster: ${{ matrix.cloudRunnerCluster }}
|
||||
- run: |
|
||||
|
||||
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
@@ -71,6 +71,9 @@ class BuildParameters {
|
||||
public garbageCollectionMaxAge!: number;
|
||||
public constantGarbageCollection!: boolean;
|
||||
public githubChecks!: boolean;
|
||||
public asyncWorkflow!: boolean;
|
||||
public githubCheckId!: string;
|
||||
public triggerWorkflowOnComplete!: string[];
|
||||
|
||||
static async create(): Promise<BuildParameters> {
|
||||
const buildFile = this.parseBuildFile(Input.buildName, Input.targetPlatform, Input.androidAppBundle);
|
||||
@@ -155,6 +158,9 @@ class BuildParameters {
|
||||
constantGarbageCollection: CloudRunnerOptions.constantGarbageCollection,
|
||||
garbageCollectionMaxAge: CloudRunnerOptions.garbageCollectionMaxAge,
|
||||
githubChecks: CloudRunnerOptions.githubChecks,
|
||||
asyncWorkflow: CloudRunnerOptions.asyncCloudRunner,
|
||||
githubCheckId: CloudRunnerOptions.githubCheckId,
|
||||
triggerWorkflowOnComplete: CloudRunnerOptions.triggerWorkflowOnComplete,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ export class Cli {
|
||||
program.parse(process.argv);
|
||||
Cli.options = program.opts();
|
||||
|
||||
return Cli.isCliMode;
|
||||
return Cli.isCliMode || process.env.GAMECI_CLI;
|
||||
}
|
||||
|
||||
static async RunCli(): Promise<void> {
|
||||
@@ -113,12 +113,16 @@ export class Cli {
|
||||
public static async asyncronousWorkflow(): Promise<string> {
|
||||
const buildParameter = await BuildParameters.create();
|
||||
const baseImage = new ImageTag(buildParameter);
|
||||
await CloudRunner.setup(buildParameter);
|
||||
|
||||
return await CloudRunner.run(buildParameter, baseImage.toString());
|
||||
}
|
||||
|
||||
@CliFunction(`checks-update`, `runs a cloud runner build`)
|
||||
public static async checksUpdate() {
|
||||
const buildParameter = await BuildParameters.create();
|
||||
|
||||
await CloudRunner.setup(buildParameter);
|
||||
const input = JSON.parse(process.env.CHECKS_UPDATE || ``);
|
||||
core.info(`Checks Update ${process.env.CHECKS_UPDATE}`);
|
||||
if (input.mode === `create`) {
|
||||
|
||||
@@ -62,6 +62,9 @@ class CloudRunnerOptions {
|
||||
static get githubChecks(): boolean {
|
||||
return CloudRunnerOptions.getInput('githubChecks') || false;
|
||||
}
|
||||
static get githubCheckId(): string {
|
||||
return CloudRunnerOptions.getInput('githubCheckId') || ``;
|
||||
}
|
||||
|
||||
static get githubOwner() {
|
||||
return CloudRunnerOptions.getInput('githubOwner') || CloudRunnerOptions.githubRepo.split(`/`)[0] || false;
|
||||
@@ -71,6 +74,10 @@ class CloudRunnerOptions {
|
||||
return CloudRunnerOptions.getInput('githubRepoName') || CloudRunnerOptions.githubRepo.split(`/`)[1] || false;
|
||||
}
|
||||
|
||||
static get triggerWorkflowOnComplete() {
|
||||
return CloudRunnerOptions.getInput('triggerWorkflowOnComplete')?.split(',') || [];
|
||||
}
|
||||
|
||||
// ### ### ###
|
||||
// Git syncronization parameters
|
||||
// ### ### ###
|
||||
@@ -242,7 +249,7 @@ class CloudRunnerOptions {
|
||||
return CloudRunnerOptions.getInput(`watchToEnd`) || true;
|
||||
}
|
||||
|
||||
static get asyncCloudRunner(): boolean {
|
||||
public static get asyncCloudRunner(): boolean {
|
||||
return (CloudRunnerOptions.getInput('asyncCloudRunner') || `false`) === `true` || false;
|
||||
}
|
||||
|
||||
@@ -251,7 +258,7 @@ class CloudRunnerOptions {
|
||||
}
|
||||
|
||||
public static get useSharedBuilder(): boolean {
|
||||
return (CloudRunnerOptions.getInput(`useSharedBuilder`) || 'true') === 'true';
|
||||
return (CloudRunnerOptions.getInput(`useSharedBuilder`) || 'false') === 'true';
|
||||
}
|
||||
|
||||
public static get useLz4Compression(): boolean {
|
||||
|
||||
@@ -23,11 +23,19 @@ class CloudRunner {
|
||||
private static cloudRunnerEnvironmentVariables: CloudRunnerEnvironmentVariable[];
|
||||
static lockedWorkspace: string | undefined;
|
||||
public static readonly retainedWorkspacePrefix: string = `retained-workspace`;
|
||||
public static githubCheckId;
|
||||
public static setup(buildParameters: BuildParameters) {
|
||||
public static get isCloudRunnerEnvironment() {
|
||||
return process.env[`GITHUB_ACTIONS`] !== `true`;
|
||||
}
|
||||
public static get isCloudRunnerAsyncEnvironment() {
|
||||
return process.env[`GAMECI_ASYNC_WORKFLOW`] === `true`;
|
||||
}
|
||||
public static async setup(buildParameters: BuildParameters) {
|
||||
CloudRunnerLogger.setup();
|
||||
CloudRunnerLogger.log(`Setting up cloud runner`);
|
||||
CloudRunner.buildParameters = buildParameters;
|
||||
if (CloudRunner.buildParameters.githubCheckId === ``) {
|
||||
CloudRunner.buildParameters.githubCheckId = await GitHub.createGitHubCheck(CloudRunner.buildParameters.buildGuid);
|
||||
}
|
||||
CloudRunner.setupSelectedBuildPlatform();
|
||||
CloudRunner.defaultSecrets = TaskParameterSerializer.readDefaultSecrets();
|
||||
CloudRunner.cloudRunnerEnvironmentVariables =
|
||||
@@ -73,10 +81,8 @@ class CloudRunner {
|
||||
}
|
||||
|
||||
static async run(buildParameters: BuildParameters, baseImage: string) {
|
||||
CloudRunner.setup(buildParameters);
|
||||
await CloudRunner.setup(buildParameters);
|
||||
try {
|
||||
CloudRunner.githubCheckId = await GitHub.createGitHubCheck(CloudRunner.buildParameters.buildGuid);
|
||||
|
||||
if (buildParameters.retainWorkspace) {
|
||||
CloudRunner.lockedWorkspace = `${CloudRunner.retainedWorkspacePrefix}-${CloudRunner.buildParameters.buildGuid}`;
|
||||
|
||||
@@ -106,7 +112,11 @@ class CloudRunner {
|
||||
CloudRunner.defaultSecrets,
|
||||
);
|
||||
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
||||
await GitHub.updateGitHubCheck(CloudRunner.buildParameters.buildGuid, CloudRunner.buildParameters.buildGuid);
|
||||
const content = { ...CloudRunner.buildParameters };
|
||||
content.gitPrivateToken = ``;
|
||||
content.unitySerial = ``;
|
||||
const jsonContent = JSON.stringify(content, undefined, 4);
|
||||
await GitHub.updateGitHubCheck(jsonContent, CloudRunner.buildParameters.buildGuid);
|
||||
const output = await new WorkflowCompositionRoot().run(
|
||||
new CloudRunnerStepState(baseImage, CloudRunner.cloudRunnerEnvironmentVariables, CloudRunner.defaultSecrets),
|
||||
);
|
||||
@@ -130,6 +140,8 @@ class CloudRunner {
|
||||
CloudRunner.lockedWorkspace = undefined;
|
||||
}
|
||||
|
||||
await GitHub.triggerWorkflowOnComplete(CloudRunner.buildParameters.triggerWorkflowOnComplete);
|
||||
|
||||
if (buildParameters.constantGarbageCollection) {
|
||||
CloudRunner.Provider.garbageCollect(``, true, buildParameters.garbageCollectionMaxAge, true, true);
|
||||
}
|
||||
|
||||
@@ -77,6 +77,9 @@ class AWSTaskRunner {
|
||||
const containerState = taskData.containers?.[0];
|
||||
const exitCode = containerState?.exitCode || undefined;
|
||||
CloudRunnerLogger.log(`Container State: ${JSON.stringify(containerState, undefined, 4)}`);
|
||||
if (exitCode === undefined) {
|
||||
CloudRunnerLogger.logWarning(`No exitcode for container`);
|
||||
}
|
||||
const wasSuccessful = exitCode === 0 || (exitCode === undefined && taskData.lastStatus === 'RUNNING');
|
||||
if (wasSuccessful) {
|
||||
CloudRunnerLogger.log(`Cloud runner job has finished successfully`);
|
||||
|
||||
@@ -129,14 +129,27 @@ class Kubernetes implements ProviderInterface {
|
||||
this.jobName = `unity-builder-job-${this.buildGuid}`;
|
||||
this.containerName = `main`;
|
||||
await KubernetesSecret.createSecret(secrets, this.secretName, this.namespace, this.kubeClient);
|
||||
await this.createNamespacedJob(commands, image, mountdir, workingdir, environment, secrets);
|
||||
this.setPodNameAndContainerName(await Kubernetes.findPodFromJob(this.kubeClient, this.jobName, this.namespace));
|
||||
CloudRunnerLogger.log('Watching pod until running');
|
||||
await KubernetesTaskRunner.watchUntilPodRunning(this.kubeClient, this.podName, this.namespace);
|
||||
let output = '';
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
try {
|
||||
let existsAlready = false;
|
||||
let status;
|
||||
try {
|
||||
status = await this.kubeClient.readNamespacedPodStatus(this.podName, this.namespace);
|
||||
CloudRunnerLogger.log(JSON.stringify(status.body.status?.containerStatuses, undefined, 4));
|
||||
existsAlready = true;
|
||||
} catch {
|
||||
// empty
|
||||
}
|
||||
if (!existsAlready || status.state?.terminated !== undefined) {
|
||||
CloudRunnerLogger.log('Job does not exist');
|
||||
await this.createNamespacedJob(commands, image, mountdir, workingdir, environment, secrets);
|
||||
const find = await Kubernetes.findPodFromJob(this.kubeClient, this.jobName, this.namespace);
|
||||
this.setPodNameAndContainerName(find);
|
||||
CloudRunnerLogger.log('Watching pod until running');
|
||||
await KubernetesTaskRunner.watchUntilPodRunning(this.kubeClient, this.podName, this.namespace);
|
||||
}
|
||||
CloudRunnerLogger.log('Pod running, streaming logs');
|
||||
output = await KubernetesTaskRunner.runTask(
|
||||
this.kubeConfig,
|
||||
@@ -163,11 +176,12 @@ class Kubernetes implements ProviderInterface {
|
||||
errorParsed = error;
|
||||
}
|
||||
|
||||
const reason = errorParsed.reason || errorParsed.response?.body?.reason || ``;
|
||||
const errorMessage = errorParsed.message || reason;
|
||||
const errorMessage =
|
||||
errorParsed.name || errorParsed.reason || errorParsed.response?.body?.reason || errorParsed.message;
|
||||
|
||||
const continueStreaming =
|
||||
errorMessage.includes(`dial timeout, backstop`) ||
|
||||
errorMessage.includes(`HttpError`) ||
|
||||
errorMessage.includes(`HttpError: HTTP request failed`) ||
|
||||
errorMessage.includes(`an error occurred when try to find container`) ||
|
||||
errorMessage.includes(`not found`) ||
|
||||
@@ -192,6 +206,18 @@ class Kubernetes implements ProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
private async doesJobExist(name) {
|
||||
const jobs = await this.kubeClientBatch.listNamespacedJob(this.namespace);
|
||||
|
||||
return jobs.body.items.some((x) => x.metadata?.name === name);
|
||||
}
|
||||
|
||||
private async doesFailedJobExist() {
|
||||
const podStatus = await this.kubeClient.readNamespacedPodStatus(this.podName, this.namespace);
|
||||
|
||||
return podStatus.body.status?.phase === `Failed`;
|
||||
}
|
||||
|
||||
private async createNamespacedJob(
|
||||
commands: string,
|
||||
image: string,
|
||||
@@ -217,12 +243,12 @@ class Kubernetes implements ProviderInterface {
|
||||
k8s,
|
||||
);
|
||||
await new Promise((promise) => setTimeout(promise, 15000));
|
||||
await this.kubeClientBatch.createNamespacedJob(this.namespace, jobSpec);
|
||||
const result = await this.kubeClientBatch.createNamespacedJob(this.namespace, jobSpec);
|
||||
CloudRunnerLogger.log(`Build job created`);
|
||||
await new Promise((promise) => setTimeout(promise, 5000));
|
||||
CloudRunnerLogger.log('Job created');
|
||||
|
||||
return;
|
||||
return result.body.metadata?.name;
|
||||
} catch (error) {
|
||||
CloudRunnerLogger.log(`Error occured creating job: ${error}`);
|
||||
throw error;
|
||||
|
||||
@@ -7,6 +7,7 @@ import waitUntil from 'async-wait-until';
|
||||
import { FollowLogStreamService } from '../../services/follow-log-stream-service';
|
||||
|
||||
class KubernetesTaskRunner {
|
||||
static lastReceivedTimestamp: number;
|
||||
static async runTask(
|
||||
kubeConfig: KubeConfig,
|
||||
kubeClient: CoreV1Api,
|
||||
@@ -33,15 +34,51 @@ class KubernetesTaskRunner {
|
||||
));
|
||||
next();
|
||||
};
|
||||
|
||||
// export interface LogOptions {
|
||||
/**
|
||||
* Follow the log stream of the pod. Defaults to false.
|
||||
*/
|
||||
// follow?: boolean;
|
||||
/**
|
||||
* If set, the number of bytes to read from the server before terminating the log output. This may not display a
|
||||
* complete final line of logging, and may return slightly more or slightly less than the specified limit.
|
||||
*/
|
||||
// limitBytes?: number;
|
||||
/**
|
||||
* If true, then the output is pretty printed.
|
||||
*/
|
||||
// pretty?: boolean;
|
||||
/**
|
||||
* Return previous terminated container logs. Defaults to false.
|
||||
*/
|
||||
// previous?: boolean;
|
||||
/**
|
||||
* A relative time in seconds before the current time from which to show logs. If this value precedes the time a
|
||||
* pod was started, only logs since the pod start will be returned. If this value is in the future, no logs will
|
||||
* be returned. Only one of sinceSeconds or sinceTime may be specified.
|
||||
*/
|
||||
// sinceSeconds?: number;
|
||||
/**
|
||||
* If set, the number of lines from the end of the logs to show. If not specified, logs are shown from the creation
|
||||
* of the container or sinceSeconds or sinceTime
|
||||
*/
|
||||
// tailLines?: number;
|
||||
/**
|
||||
* If true, add an RFC3339 or RFC3339Nano timestamp at the beginning of every line of log output. Defaults to false.
|
||||
*/
|
||||
// timestamps?: boolean;
|
||||
// }
|
||||
|
||||
const logOptions = {
|
||||
follow: true,
|
||||
pretty: false,
|
||||
previous: false,
|
||||
previous: true,
|
||||
timestamps: true,
|
||||
sinceSeconds: KubernetesTaskRunner.lastReceivedTimestamp,
|
||||
};
|
||||
try {
|
||||
const resultError = await new Promise((resolve) =>
|
||||
new Log(kubeConfig).log(namespace, podName, containerName, stream, resolve, logOptions),
|
||||
);
|
||||
const resultError = await new Log(kubeConfig).log(namespace, podName, containerName, stream, logOptions);
|
||||
stream.destroy();
|
||||
if (resultError) {
|
||||
throw resultError;
|
||||
@@ -73,6 +110,8 @@ class KubernetesTaskRunner {
|
||||
if (stream) {
|
||||
stream.destroy();
|
||||
}
|
||||
CloudRunnerLogger.log(JSON.stringify(error));
|
||||
CloudRunnerLogger.log('k8s task runner failed');
|
||||
throw error;
|
||||
}
|
||||
CloudRunnerLogger.log('end of log stream');
|
||||
|
||||
@@ -10,6 +10,7 @@ import CloudRunnerLogger from '../services/cloud-runner-logger';
|
||||
import { CliFunction } from '../../cli/cli-functions-repository';
|
||||
import { CloudRunnerSystem } from '../services/cloud-runner-system';
|
||||
import YAML from 'yaml';
|
||||
import GitHub from '../../github';
|
||||
|
||||
export class RemoteClient {
|
||||
public static async bootstrapRepository() {
|
||||
@@ -20,7 +21,7 @@ export class RemoteClient {
|
||||
);
|
||||
process.chdir(CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.repoPathAbsolute));
|
||||
await RemoteClient.cloneRepoWithoutLFSFiles();
|
||||
RemoteClient.replaceLargePackageReferencesWithSharedReferences();
|
||||
await RemoteClient.replaceLargePackageReferencesWithSharedReferences();
|
||||
await RemoteClient.sizeOfFolder(
|
||||
'repo before lfs cache pull',
|
||||
CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.repoPathAbsolute),
|
||||
@@ -95,7 +96,12 @@ export class RemoteClient {
|
||||
assert(fs.existsSync(`.git`), 'git folder exists');
|
||||
RemoteClientLogger.log(`${CloudRunner.buildParameters.branch}`);
|
||||
await CloudRunnerSystem.Run(`git checkout ${CloudRunner.buildParameters.branch}`);
|
||||
await CloudRunnerSystem.Run(`git checkout ${CloudRunner.buildParameters.gitSha}`);
|
||||
if (CloudRunner.buildParameters.gitSha !== undefined) {
|
||||
await CloudRunnerSystem.Run(`git checkout ${CloudRunner.buildParameters.gitSha}`);
|
||||
} else {
|
||||
RemoteClientLogger.log(`buildParameter Git Sha is empty`);
|
||||
}
|
||||
|
||||
assert(fs.existsSync(path.join(`.git`, `lfs`)), 'LFS folder should not exist before caching');
|
||||
RemoteClientLogger.log(`Checked out ${CloudRunner.buildParameters.branch}`);
|
||||
} catch (error) {
|
||||
@@ -104,16 +110,17 @@ export class RemoteClient {
|
||||
}
|
||||
}
|
||||
|
||||
static replaceLargePackageReferencesWithSharedReferences() {
|
||||
static async replaceLargePackageReferencesWithSharedReferences() {
|
||||
CloudRunnerLogger.log(`Use Shared Pkgs ${CloudRunner.buildParameters.useSharedLargePackages}`);
|
||||
GitHub.updateGitHubCheck(`Use Shared Pkgs ${CloudRunner.buildParameters.useSharedLargePackages}`, ``);
|
||||
if (CloudRunner.buildParameters.useSharedLargePackages) {
|
||||
await CloudRunnerSystem.Run(`tree -L 2 ${CloudRunnerFolders.projectPathAbsolute}`);
|
||||
const filePath = path.join(CloudRunnerFolders.projectPathAbsolute, `Packages/manifest.json`);
|
||||
let manifest = fs.readFileSync(filePath, 'utf8');
|
||||
manifest = manifest.replace(/LargeContent/g, '../../../LargeContent');
|
||||
fs.writeFileSync(filePath, manifest);
|
||||
if (CloudRunner.buildParameters.cloudRunnerDebug) {
|
||||
CloudRunnerLogger.log(`Package Manifest`);
|
||||
CloudRunnerLogger.log(manifest);
|
||||
}
|
||||
CloudRunnerLogger.log(`Package Manifest \n ${manifest}`);
|
||||
GitHub.updateGitHubCheck(`Package Manifest \n ${manifest}`, ``);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +163,6 @@ export class RemoteClient {
|
||||
if (!CloudRunner.buildParameters.retainWorkspace) {
|
||||
return;
|
||||
}
|
||||
RemoteClientLogger.log(`Retained Workspace: ${CloudRunner.lockedWorkspace}`);
|
||||
RemoteClientLogger.log(`Retained Workspace: ${CloudRunner.lockedWorkspace !== undefined}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { CloudRunnerStatics } from '../cloud-runner-statics';
|
||||
import GitHub from '../../github';
|
||||
|
||||
export class FollowLogStreamService {
|
||||
static errors = ``;
|
||||
public static handleIteration(message, shouldReadLogs, shouldCleanup, output) {
|
||||
if (message.includes(`---${CloudRunner.buildParameters.logId}`)) {
|
||||
CloudRunnerLogger.log('End of log transmission received');
|
||||
@@ -17,10 +18,27 @@ export class FollowLogStreamService {
|
||||
GitHub.updateGitHubCheck(`Build succeeded`, `Build succeeded`);
|
||||
core.setOutput('build-result', 'success');
|
||||
} else if (message.includes('Build fail')) {
|
||||
GitHub.updateGitHubCheck(`Build failed`, `Build failed`);
|
||||
GitHub.updateGitHubCheck(
|
||||
`Build failed\n${FollowLogStreamService.errors}`,
|
||||
`Build failed`,
|
||||
`failure`,
|
||||
`completed`,
|
||||
);
|
||||
core.setOutput('build-result', 'failed');
|
||||
core.setFailed('unity build failed');
|
||||
core.error('BUILD FAILED!');
|
||||
} else if (message.toLowerCase().includes('error ')) {
|
||||
FollowLogStreamService.errors += `\n${message}`;
|
||||
} else if (message.toLowerCase().includes('command failed: ')) {
|
||||
FollowLogStreamService.errors += `\n${message}`;
|
||||
} else if (message.toLowerCase().includes('error: ')) {
|
||||
FollowLogStreamService.errors += `\n${message}`;
|
||||
} else if (message.toLowerCase().includes('invalid ')) {
|
||||
FollowLogStreamService.errors += `\n${message}`;
|
||||
} else if (message.toLowerCase().includes('incompatible ')) {
|
||||
FollowLogStreamService.errors += `\n${message}`;
|
||||
} else if (message.toLowerCase().includes('cannot be found')) {
|
||||
FollowLogStreamService.errors += `\n${message}`;
|
||||
} else if (CloudRunner.buildParameters.cloudRunnerDebug && message.includes(': Listening for Jobs')) {
|
||||
core.setOutput('cloud runner stop watching', 'true');
|
||||
shouldReadLogs = false;
|
||||
|
||||
@@ -11,6 +11,9 @@ export class AsyncWorkflow {
|
||||
): Promise<string> {
|
||||
try {
|
||||
CloudRunnerLogger.log(`Cloud Runner is running async mode`);
|
||||
const asyncEnvironmentVariable = new CloudRunnerEnvironmentVariable();
|
||||
asyncEnvironmentVariable.name = `GAMECI_ASYNC_WORKFLOW`;
|
||||
asyncEnvironmentVariable.value = `true`;
|
||||
|
||||
let output = '';
|
||||
|
||||
@@ -34,7 +37,7 @@ aws --version
|
||||
node /builder/dist/index.js -m async-workflow`,
|
||||
`/${CloudRunnerFolders.buildVolumeFolder}`,
|
||||
`/${CloudRunnerFolders.buildVolumeFolder}/`,
|
||||
environmentVariables,
|
||||
[...environmentVariables, asyncEnvironmentVariable],
|
||||
[
|
||||
...secrets,
|
||||
...[
|
||||
|
||||
@@ -9,7 +9,11 @@ import { AsyncWorkflow } from './async-workflow';
|
||||
export class WorkflowCompositionRoot implements WorkflowInterface {
|
||||
async run(cloudRunnerStepState: CloudRunnerStepState) {
|
||||
try {
|
||||
if (CloudRunnerOptions.asyncCloudRunner) {
|
||||
if (
|
||||
CloudRunnerOptions.asyncCloudRunner &&
|
||||
!CloudRunner.isCloudRunnerAsyncEnvironment &&
|
||||
!CloudRunner.isCloudRunnerEnvironment
|
||||
) {
|
||||
return await AsyncWorkflow.runAsyncWorkflow(cloudRunnerStepState.environment, cloudRunnerStepState.secrets);
|
||||
}
|
||||
|
||||
|
||||
+52
-16
@@ -9,6 +9,7 @@ class GitHub {
|
||||
private static longDescriptionContent: string = ``;
|
||||
private static startedDate: string;
|
||||
private static endedDate: string;
|
||||
static result: string = ``;
|
||||
private static get octokitDefaultToken() {
|
||||
return new Octokit({
|
||||
auth: process.env.GITHUB_TOKEN,
|
||||
@@ -32,7 +33,7 @@ class GitHub {
|
||||
}
|
||||
|
||||
private static get checkRunId() {
|
||||
return CloudRunner.githubCheckId;
|
||||
return CloudRunner.buildParameters.githubCheckId;
|
||||
}
|
||||
|
||||
private static get owner() {
|
||||
@@ -44,13 +45,12 @@ class GitHub {
|
||||
}
|
||||
|
||||
public static async createGitHubCheck(summary) {
|
||||
if (!CloudRunnerOptions.githubChecks) {
|
||||
if (!CloudRunnerOptions.githubChecks || CloudRunner.isCloudRunnerEnvironment) {
|
||||
return ``;
|
||||
}
|
||||
GitHub.startedDate = new Date().toISOString();
|
||||
|
||||
CloudRunnerLogger.log(`POST /repos/${GitHub.owner}/${GitHub.repo}/check-runs`);
|
||||
|
||||
CloudRunnerLogger.log(`Creating inital github check`);
|
||||
const data = {
|
||||
owner: GitHub.owner,
|
||||
repo: GitHub.repo,
|
||||
@@ -77,15 +77,20 @@ class GitHub {
|
||||
};
|
||||
const result = await GitHub.createGitHubCheckRequest(data);
|
||||
|
||||
return result.data.id;
|
||||
return result.data.id.toString();
|
||||
}
|
||||
|
||||
public static async updateGitHubCheck(longDescription, summary, result = `neutral`, status = `in_progress`) {
|
||||
if (!CloudRunnerOptions.githubChecks) {
|
||||
const isLocalAsync = CloudRunner.buildParameters.asyncWorkflow && !CloudRunner.isCloudRunnerAsyncEnvironment;
|
||||
if (!CloudRunnerOptions.githubChecks || isLocalAsync) {
|
||||
return;
|
||||
}
|
||||
GitHub.longDescriptionContent += `\n${longDescription}`;
|
||||
|
||||
if (GitHub.result !== `success` && GitHub.result !== `failure`) {
|
||||
GitHub.result = result;
|
||||
} else {
|
||||
result = GitHub.result;
|
||||
}
|
||||
const data: any = {
|
||||
owner: GitHub.owner,
|
||||
repo: GitHub.repo,
|
||||
@@ -114,11 +119,13 @@ class GitHub {
|
||||
data.conclusion = result;
|
||||
}
|
||||
|
||||
if (await CloudRunnerOptions.asyncCloudRunner) {
|
||||
if (CloudRunner.isCloudRunnerAsyncEnvironment) {
|
||||
CloudRunnerLogger.log(`Updating check via async update workflow`);
|
||||
await GitHub.runUpdateAsyncChecksWorkflow(data, `update`);
|
||||
|
||||
return;
|
||||
}
|
||||
CloudRunnerLogger.log(`Updating check via direct call`);
|
||||
await GitHub.updateGitHubCheckRequest(data);
|
||||
}
|
||||
|
||||
@@ -134,18 +141,16 @@ class GitHub {
|
||||
if (mode === `create`) {
|
||||
throw new Error(`Not supported: only use update`);
|
||||
}
|
||||
const workflowsResult = await GitHub.octokitDefaultToken.request(
|
||||
`GET /repos/${GitHub.owner}/${GitHub.repo}/actions/workflows`,
|
||||
{
|
||||
owner: GitHub.owner,
|
||||
repo: GitHub.repo,
|
||||
},
|
||||
);
|
||||
const workflowsResult = await GitHub.octokitPAT.request(`GET /repos/{owner}/{repo}/actions/workflows`, {
|
||||
owner: GitHub.owner,
|
||||
repo: GitHub.repo,
|
||||
});
|
||||
const workflows = workflowsResult.data.workflows;
|
||||
CloudRunnerLogger.log(`Got ${workflows.length} workflows`);
|
||||
let selectedId = ``;
|
||||
for (let index = 0; index < workflowsResult.data.total_count; index++) {
|
||||
if (workflows[index].name === GitHub.asyncChecksApiWorkflowName) {
|
||||
selectedId = workflows[index].id;
|
||||
selectedId = workflows[index].id.toString();
|
||||
}
|
||||
}
|
||||
if (selectedId === ``) {
|
||||
@@ -163,6 +168,37 @@ class GitHub {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
static async triggerWorkflowOnComplete(triggerWorkflowOnComplete: string[]) {
|
||||
const workflowsResult = await GitHub.octokitPAT.request(`GET /repos/{owner}/{repo}/actions/workflows`, {
|
||||
owner: GitHub.owner,
|
||||
repo: GitHub.repo,
|
||||
});
|
||||
const workflows = workflowsResult.data.workflows;
|
||||
CloudRunnerLogger.log(`Got ${workflows.length} workflows`);
|
||||
for (const element of triggerWorkflowOnComplete) {
|
||||
let selectedId = ``;
|
||||
for (let index = 0; index < workflowsResult.data.total_count; index++) {
|
||||
if (workflows[index].name === element) {
|
||||
selectedId = workflows[index].id.toString();
|
||||
}
|
||||
}
|
||||
if (selectedId === ``) {
|
||||
core.info(JSON.stringify(workflows));
|
||||
throw new Error(`no workflow with name "${GitHub.asyncChecksApiWorkflowName}"`);
|
||||
}
|
||||
await GitHub.octokitPAT.request(`POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches`, {
|
||||
owner: GitHub.owner,
|
||||
repo: GitHub.repo,
|
||||
// eslint-disable-next-line camelcase
|
||||
workflow_id: selectedId,
|
||||
ref: CloudRunnerOptions.branch,
|
||||
inputs: {
|
||||
buildGuid: CloudRunner.buildParameters.buildGuid,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default GitHub;
|
||||
|
||||
+4
-4
@@ -64,8 +64,8 @@ class Input {
|
||||
static get gitSha() {
|
||||
if (Input.getInput(`GITHUB_SHA`)) {
|
||||
return Input.getInput(`GITHUB_SHA`);
|
||||
} else if (Input.getInput(`GitSHA`)) {
|
||||
return Input.getInput(`GitSHA`);
|
||||
} else if (Input.getInput(`GitSha`)) {
|
||||
return Input.getInput(`GitSha`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ class Input {
|
||||
}
|
||||
|
||||
static get runNumber() {
|
||||
return Input.getInput('GITHUB_RUN_NUMBER') || '0';
|
||||
return Input.getInput('GITHUB_RUN_NUMBER') || Input.getInput('runNumber') || '0';
|
||||
}
|
||||
|
||||
static get targetPlatform() {
|
||||
@@ -168,7 +168,7 @@ class Input {
|
||||
}
|
||||
|
||||
static get gitPrivateToken() {
|
||||
return core.getInput('gitPrivateToken') || false;
|
||||
return Input.getInput('gitPrivateToken') || false;
|
||||
}
|
||||
|
||||
static get chownFilesTo() {
|
||||
|
||||
Reference in New Issue
Block a user