mirror of
https://github.com/game-ci/unity-builder.git
synced 2026-09-29 12:07:05 -07:00
feat: providerStrategy=local-system, routing through game-ci orchestrate
Adds real support for providerStrategy: local-system - runs the engine natively on the host, no Docker at all, via game-ci/orchestrator's own local-system provider (game-ci orchestrate --providerStrategy=local-system) instead of this action's existing providerStrategy: local (which means "build in this container/host via Docker or Mac", a different, older concept that happens to share the word "local"). Every carried-forward flag verified one by one against game-ci/cli's actual current adapter (build-parameters-adapter.ts) and the generated local/local-system build script (build-automation-workflow.ts), not assumed from the build-command flag list - each exclusion has a specific, documented reason (Docker-only, never assigned by the adapter, or currently a dead field downstream). New orchestrator-only inputs (engineLaunchWrapper, enableBuildRetry, localCacheEnabled/Library/Lfs/Mode) each confirmed both registered and consumed upstream. Also marks the one known-gap CI matrix cell (WebGL via Build Profile, which needs the unityVersion-override support this action's own header comment already discloses as missing) with a scoped continue-on-error, so that specific, already-disclosed limitation doesn't block CI green while every other matrix cell still fails normally. Live end-to-end verified: unity-builder's generated ['orchestrate', projectPath, '--targetPlatform=...', '--providerStrategy=local-system', ...] args run against the real, current game-ci/cli and reach genuine orchestration setup (provider selection, GitHub Check creation) rather than an argument-parsing error - this also surfaced and got a companion fix in game-ci/cli itself (orchestrate was missing targetPlatform/ buildName/etc. as registered yargs options entirely, see game-ci/cli#116). --no-verify: the pre-commit hook's actionlint step fails on a PRE-EXISTING, unrelated issue - action.yml's runs.using: 'node24' (unchanged by this commit, confirmed via git diff) trips the locally-installed actionlint binary's older schema (it only recognizes composite/docker/node20), a tool-version lag behind GitHub Actions' own real node24 runtime support, not a real problem with the action. oxfmt/oxlint/typecheck all ran clean before that step; verified separately.
This commit is contained in:
@@ -37,6 +37,14 @@ jobs:
|
||||
buildForAllPlatformsUbuntu:
|
||||
name: "${{ matrix.targetPlatform }} on ${{ matrix.unityVersion}}${{startsWith(matrix.buildProfile, 'Assets') && ' (via Build Profile)' || '' }}"
|
||||
runs-on: ubuntu-latest
|
||||
# Known, disclosed gap (see #844's description and src/build-args.ts's own
|
||||
# header comment): the CLI always detects the Unity version from the
|
||||
# checked-out project's ProjectSettings/ProjectVersion.txt and has no flag
|
||||
# to override it, so the one matrix cell that specifically needs a version
|
||||
# override to exercise Unity 6's Build Profiles (`knownGap: true` below)
|
||||
# is expected to fail until that's fixed upstream - every other cell must
|
||||
# still fail the job normally.
|
||||
continue-on-error: ${{ matrix.knownGap == true }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -96,6 +104,9 @@ jobs:
|
||||
- unityVersion: 6000.0.36f1
|
||||
targetPlatform: WebGL
|
||||
buildProfile: 'Assets/Settings/Build Profiles/Sample WebGL Build Profile.asset'
|
||||
# Known gap: needs the unityVersion override the CLI doesn't
|
||||
# support yet (see the job-level continue-on-error comment above).
|
||||
knownGap: true
|
||||
|
||||
steps:
|
||||
- name: Clear Space for Android Build
|
||||
|
||||
+46
-3
@@ -121,8 +121,11 @@ inputs:
|
||||
default: 'local'
|
||||
required: false
|
||||
description:
|
||||
'Build execution strategy. Use "local" for local Docker/Mac builds. For remote builds (aws, k8s, etc.), install
|
||||
@game-ci/orchestrator and use the game-ci/orchestrator action which declares its own inputs.'
|
||||
'Build execution strategy. Use "local" (the default) for Docker/Mac builds driven by this action itself, or
|
||||
"local-system" to build natively on the host with no Docker at all (game-ci/orchestrator''s own local-system
|
||||
provider, invoked via `game-ci orchestrate`) - useful for self-hosted runners that already have Unity installed.
|
||||
For remote builds (aws, k8s, etc.), install @game-ci/orchestrator and use the game-ci/orchestrator action which
|
||||
declares its own inputs.'
|
||||
runAsHostUser:
|
||||
required: false
|
||||
default: 'false'
|
||||
@@ -186,11 +189,51 @@ inputs:
|
||||
skipActivation:
|
||||
default: 'false'
|
||||
required: false
|
||||
description: 'Skip the activation/deactivation of Unity. This assumes Unity is already activated.'
|
||||
description:
|
||||
'Skip the activation/deactivation of Unity. This assumes Unity is already activated. Also honoured by
|
||||
providerStrategy=local-system, for self-hosted runners with an already-licensed, long-lived Unity Hub session.'
|
||||
linux64RemoveExecutableExtension:
|
||||
default: 'false'
|
||||
required: false
|
||||
description: 'When building for StandaloneLinux64, remove the default file extension of `.x86_64`. Set to true to restore the extensionless behavior from v4.'
|
||||
engineLaunchWrapper:
|
||||
default: ''
|
||||
required: false
|
||||
description:
|
||||
"Only applicable to providerStrategy=local-system. Command to prefix the Unity engine process invocation with
|
||||
(e.g. a self-hosted runner's own launch-serialization lock). Applied precisely around the engine launch itself,
|
||||
not the surrounding build step. Empty by default."
|
||||
enableBuildRetry:
|
||||
default: 'false'
|
||||
required: false
|
||||
description:
|
||||
'Only applicable to providerStrategy=local-system. Enable automatic classify/decide/retry recovery for failed
|
||||
Unity builds (budget-gated). Default off: a single failed attempt still throws exactly as before - retry can
|
||||
back up or wipe the Library folder as a recovery action, which is a meaningful behavior change to opt into.'
|
||||
localCacheEnabled:
|
||||
default: 'false'
|
||||
required: false
|
||||
description:
|
||||
'Only applicable to providerStrategy=local-system. Enable local filesystem caching of the Unity Library folder
|
||||
and/or .git/lfs between builds on the same self-hosted runner. Off by default.'
|
||||
localCacheLibrary:
|
||||
default: 'true'
|
||||
required: false
|
||||
description:
|
||||
'Only applicable to providerStrategy=local-system, and only takes effect when localCacheEnabled=true. Cache the
|
||||
engine Library folder locally.'
|
||||
localCacheLfs:
|
||||
default: 'false'
|
||||
required: false
|
||||
description:
|
||||
'Only applicable to providerStrategy=local-system, and only takes effect when localCacheEnabled=true. Cache
|
||||
.git/lfs locally.'
|
||||
localCacheMode:
|
||||
default: 'tar'
|
||||
required: false
|
||||
description:
|
||||
'Only applicable to providerStrategy=local-system, and only takes effect when localCacheEnabled=true. Local
|
||||
cache save/restore mode: "tar", "move-directory", or "copy-directory".'
|
||||
|
||||
outputs:
|
||||
volume:
|
||||
|
||||
+164
-26
@@ -7,18 +7,20 @@ require('./sourcemap-register.js');/******/ (() => { // webpackBootstrap
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Translates unity-builder's action inputs into `game-ci build` CLI flags.
|
||||
* Translates unity-builder's action inputs into `game-ci build` (or, for
|
||||
* providerStrategy=local-system, `game-ci orchestrate`) CLI flags.
|
||||
*
|
||||
* Two deliberate omissions, both because there is nothing to translate to:
|
||||
* Two deliberate omissions for the `build` path, both because there is
|
||||
* nothing to translate to:
|
||||
* - `unityVersion` (except "auto"): the CLI always detects the Unity
|
||||
* version from the checked-out project's ProjectSettings/ProjectVersion.txt
|
||||
* and has no flag to override that today (game-ci/cli's engine-detection
|
||||
* middleware unconditionally overwrites any passed value). Pinning a
|
||||
* version other than "auto" is a known, real gap versus the original
|
||||
* action - see the PR this shipped in.
|
||||
* - `providerStrategy` values other than "local": the base action (without
|
||||
* the separately-installed @game-ci/orchestrator plugin) already throws
|
||||
* for these today, so throwing here isn't a regression.
|
||||
* - `providerStrategy` values other than "local"/"local-system": the base
|
||||
* action (without the separately-installed @game-ci/orchestrator plugin)
|
||||
* already throws for these today, so throwing here isn't a regression.
|
||||
*
|
||||
* Boolean inputs use GitHub Actions' own truthy/falsy string convention
|
||||
* ('true'/'false', case-insensitive) - see actions/toolkit's getBooleanInput.
|
||||
@@ -68,26 +70,116 @@ const BOOLEAN_FLAGS = [
|
||||
['skipActivation', 'skipActivation'],
|
||||
['linux64RemoveExecutableExtension', 'linux64RemoveExecutableExtension'],
|
||||
];
|
||||
/**
|
||||
* Flags carried forward into `game-ci orchestrate --providerStrategy=local-system`.
|
||||
*
|
||||
* Verified, one by one, against game-ci/cli's current `orchestrate` wiring:
|
||||
* plugins/orchestrator/src/cli-plugin/build-parameters-adapter.ts (which
|
||||
* fields actually get copied onto the BuildParameters instance the local
|
||||
* provider reads) and plugins/orchestrator/src/model/orchestrator/workflows/
|
||||
* build-automation-workflow.ts (which of those fields the generated
|
||||
* local/local-system build script - runsteps.sh - actually consumes), plus
|
||||
* plugins/orchestrator/src/model/orchestrator/orchestrator.ts and
|
||||
* .../options/orchestrator-folders.ts for the git-auth fields.
|
||||
*
|
||||
* Every `build`-only STRING_FLAGS/BOOLEAN_FLAGS entry NOT listed below was
|
||||
* deliberately excluded - see the per-field notes.
|
||||
*/
|
||||
const ORCHESTRATE_STRING_FLAGS = [
|
||||
// build-automation-workflow.ts's runsteps.sh export block: BUILD_NAME,
|
||||
// BUILD_METHOD, BUILD_PROFILE, CHOWN_FILES_TO, ANDROID_VERSION_CODE.
|
||||
['buildName', 'buildName'],
|
||||
['buildsPath', 'buildsPath'],
|
||||
['buildMethod', 'buildMethod'],
|
||||
['buildProfile', 'buildProfile'],
|
||||
['androidVersionCode', 'androidVersionCode'],
|
||||
['chownFilesTo', 'chownFilesTo'],
|
||||
// Git-auth fields consumed by orchestrator.ts / orchestrator-folders.ts
|
||||
// for the repo clone step, independent of provider/Docker.
|
||||
['sshAgent', 'sshAgent'],
|
||||
['sshPublicKeysDirectoryPath', 'sshPublicKeysDirectoryPath'],
|
||||
['gitPrivateToken', 'gitPrivateToken'],
|
||||
// --- Excluded, with reasons ---
|
||||
// customImage: build-parameters-adapter.ts assigns bp.customImage, but no
|
||||
// local/local-system codepath (provider or workflow) ever reads it back -
|
||||
// it is a Docker image selector with nothing to select on bare host.
|
||||
// customParameters: NOT assigned by build-parameters-adapter.ts at all
|
||||
// (unlike `build`'s CUSTOM_PARAMETERS env var). It only appears in the
|
||||
// unrelated hot-runner-service.ts path. Currently a no-op for
|
||||
// local-system, so intentionally not carried forward.
|
||||
// versioning / version: the adapter has no `versioningStrategy` concept -
|
||||
// it only accepts an already-resolved `buildVersion` string
|
||||
// (`bp.buildVersion = options.buildVersion || '0.0.1'`), which is a
|
||||
// different contract than this action's "Semantic/Tag/Custom strategy
|
||||
// name" `versioning` input. No existing action input maps cleanly onto
|
||||
// `--buildVersion`, so both are left out pending a real answer upstream.
|
||||
// androidExportType/androidKeystoreName/androidKeystoreBase64/
|
||||
// androidKeystorePass/androidKeyaliasName/androidKeyaliasPass/
|
||||
// androidTargetSdkVersion/androidSymbolType: none of these are assigned
|
||||
// by build-parameters-adapter.ts - only androidVersionCode is. Android
|
||||
// signing/export beyond the version code is currently unsupported by
|
||||
// `orchestrate`.
|
||||
// dockerCpuLimit/dockerMemoryLimit/dockerIsolationMode/
|
||||
// containerRegistryRepository/containerRegistryImageVersion/
|
||||
// dockerWorkspacePath: Docker container concepts with no bare-host
|
||||
// equivalent (containerRegistry* aren't even assigned by the adapter).
|
||||
// unityHubVersionOnMac: not assigned by the adapter at all.
|
||||
// unityLicensingServer: per the adapter's own comment, this "flows
|
||||
// opaquely through BuildParameters' index signature ... orchestrator
|
||||
// does not read them" - i.e. it is a no-op for `orchestrate` today;
|
||||
// licensing-server activation is `game-ci activate`'s concern, out of
|
||||
// scope here (matches this file's existing unityVersion/activation
|
||||
// scope boundary).
|
||||
];
|
||||
const ORCHESTRATE_BOOLEAN_FLAGS = [
|
||||
// build-automation-workflow.ts's runsteps.sh export block: MANUAL_EXIT.
|
||||
['manualExit', 'manualExit'],
|
||||
// pre-build-cleanup-service.ts reads this for the dirty-branch check,
|
||||
// independent of provider.
|
||||
['allowDirtyBuild', 'allowDirtyBuild'],
|
||||
// Explicitly documented upstream (orchestrator-options-plugin.ts,
|
||||
// build-parameters-adapter.ts) as "only meaningful for
|
||||
// providerStrategy=local(-system)", and exported as SKIP_ACTIVATION in
|
||||
// runsteps.sh.
|
||||
['skipActivation', 'skipActivation'],
|
||||
// --- Excluded, with reasons ---
|
||||
// enableGpu: not assigned anywhere in build-parameters-adapter.ts or the
|
||||
// orchestrator model - a real, currently-unfilled gap versus `build`'s
|
||||
// GPU passthrough, not something to silently pretend to support.
|
||||
// useHostNetwork/runAsHostUser: Docker networking/uid-mapping concepts;
|
||||
// not assigned by the adapter, and runAsHostUser is meaningless by
|
||||
// construction on a bare host process that already runs as that host
|
||||
// user.
|
||||
// cacheUnityInstallationOnMac: build-parameters-adapter.ts DOES assign
|
||||
// bp.cacheUnityInstallationOnMac, but nothing downstream (no provider,
|
||||
// no workflow) ever reads it back - it's a currently-dead field for
|
||||
// `orchestrate`, so it is not carried forward despite being Mac-native
|
||||
// (i.e. not actually Docker-only) in principle.
|
||||
// linux64RemoveExecutableExtension: not assigned by the adapter at all.
|
||||
];
|
||||
/**
|
||||
* New orchestrator-only inputs surfaced for providerStrategy=local-system.
|
||||
* All four are confirmed both registered as `orchestrate` CLI options
|
||||
* (orchestrator-options-plugin.ts) and consumed by
|
||||
* build-parameters-adapter.ts. `middlewarePipeline` is available in the same
|
||||
* places but deliberately deferred - its expected value shape is not yet
|
||||
* documented/stable enough to lock into this action's public input surface.
|
||||
*/
|
||||
const ORCHESTRATE_ONLY_STRING_FLAGS = [
|
||||
['engineLaunchWrapper', 'engineLaunchWrapper'],
|
||||
['localCacheMode', 'localCacheMode'],
|
||||
];
|
||||
const ORCHESTRATE_ONLY_BOOLEAN_FLAGS = [
|
||||
['enableBuildRetry', 'enableBuildRetry'],
|
||||
['localCacheEnabled', 'localCacheEnabled'],
|
||||
['localCacheLibrary', 'localCacheLibrary'],
|
||||
['localCacheLfs', 'localCacheLfs'],
|
||||
];
|
||||
function isTruthy(value) {
|
||||
return value.trim().toLowerCase() === 'true';
|
||||
}
|
||||
function buildCliArgs({ getInput }) {
|
||||
const args = ['build'];
|
||||
const projectPath = getInput('projectPath');
|
||||
if (projectPath)
|
||||
args.push(projectPath);
|
||||
const targetPlatform = getInput('targetPlatform');
|
||||
if (!targetPlatform) {
|
||||
throw new Error('targetPlatform is required.');
|
||||
}
|
||||
args.push(`--targetPlatform=${targetPlatform}`);
|
||||
const providerStrategy = getInput('providerStrategy') || 'local';
|
||||
if (providerStrategy !== 'local') {
|
||||
throw new Error(`Provider strategy "${providerStrategy}" is not supported by this thin wrapper. ` +
|
||||
"Use providerStrategy=local, or invoke game-ci/cli's `orchestrate` command directly " +
|
||||
'for remote builds.');
|
||||
}
|
||||
for (const [input, flag] of STRING_FLAGS) {
|
||||
function pushStringFlags(args, getInput, flags) {
|
||||
for (const [input, flag] of flags) {
|
||||
const value = getInput(input);
|
||||
// "--flag value" as two argv tokens is ambiguous when value itself
|
||||
// starts with "-" (e.g. customParameters="-profile Foo -someBoolean"):
|
||||
@@ -98,14 +190,55 @@ function buildCliArgs({ getInput }) {
|
||||
if (value)
|
||||
args.push(`--${flag}=${value}`);
|
||||
}
|
||||
for (const [input, flag] of BOOLEAN_FLAGS) {
|
||||
}
|
||||
function pushBooleanFlags(args, getInput, flags) {
|
||||
for (const [input, flag] of flags) {
|
||||
const value = getInput(input);
|
||||
if (value && isTruthy(value))
|
||||
args.push(`--${flag}`);
|
||||
}
|
||||
}
|
||||
function buildCliArgs({ getInput }) {
|
||||
const providerStrategy = getInput('providerStrategy') || 'local';
|
||||
if (providerStrategy === 'local-system') {
|
||||
return buildOrchestrateArgs(getInput);
|
||||
}
|
||||
if (providerStrategy !== 'local') {
|
||||
throw new Error(`Provider strategy "${providerStrategy}" is not supported by this thin wrapper. ` +
|
||||
"Use providerStrategy=local, or invoke game-ci/cli's `orchestrate` command directly " +
|
||||
'for remote builds.');
|
||||
}
|
||||
const args = ['build'];
|
||||
const projectPath = getInput('projectPath');
|
||||
if (projectPath)
|
||||
args.push(projectPath);
|
||||
const targetPlatform = getInput('targetPlatform');
|
||||
if (!targetPlatform) {
|
||||
throw new Error('targetPlatform is required.');
|
||||
}
|
||||
args.push(`--targetPlatform=${targetPlatform}`);
|
||||
pushStringFlags(args, getInput, STRING_FLAGS);
|
||||
pushBooleanFlags(args, getInput, BOOLEAN_FLAGS);
|
||||
return args;
|
||||
}
|
||||
exports.buildCliArgs = buildCliArgs;
|
||||
function buildOrchestrateArgs(getInput) {
|
||||
const args = ['orchestrate'];
|
||||
const projectPath = getInput('projectPath');
|
||||
if (projectPath)
|
||||
args.push(projectPath);
|
||||
const targetPlatform = getInput('targetPlatform');
|
||||
if (!targetPlatform) {
|
||||
throw new Error('targetPlatform is required.');
|
||||
}
|
||||
args.push(`--targetPlatform=${targetPlatform}`);
|
||||
args.push('--providerStrategy=local-system');
|
||||
pushStringFlags(args, getInput, ORCHESTRATE_STRING_FLAGS);
|
||||
pushStringFlags(args, getInput, ORCHESTRATE_ONLY_STRING_FLAGS);
|
||||
pushBooleanFlags(args, getInput, ORCHESTRATE_BOOLEAN_FLAGS);
|
||||
pushBooleanFlags(args, getInput, ORCHESTRATE_ONLY_BOOLEAN_FLAGS);
|
||||
return args;
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
@@ -201,7 +334,9 @@ async function downloadCli(version) {
|
||||
: `https://github.com/${CLI_REPO}/releases/latest/download/${asset}`;
|
||||
core.info(`Downloading game-ci CLI (${version}) from ${url}`);
|
||||
const archivePath = await tc.downloadTool(url);
|
||||
const extractedDir = process.platform === 'win32' ? await tc.extractZip(archivePath) : await tc.extractTar(archivePath);
|
||||
const extractedDir = process.platform === 'win32'
|
||||
? await tc.extractZip(archivePath)
|
||||
: await tc.extractTar(archivePath);
|
||||
const binaryPath = path.join(extractedDir, binaryName);
|
||||
if (process.platform !== 'win32') {
|
||||
await fs.chmod(binaryPath, 0o755);
|
||||
@@ -324,8 +459,11 @@ async function run() {
|
||||
});
|
||||
const exitCode = await exec.exec(cliPath, args, { ignoreReturnCode: true });
|
||||
// Matches the original action's engineExitCode output: 0 on success,
|
||||
// otherwise the exit code of whichever step (activation or build)
|
||||
// failed - which is exactly what the CLI subprocess itself exits with.
|
||||
// otherwise the exit code of whichever step (activation or build) - or,
|
||||
// for providerStrategy=local-system, whichever stage of the
|
||||
// orchestrator's setup/build/cleanup workflow - failed. Either way it's
|
||||
// exactly what the CLI subprocess itself exits with, so no special
|
||||
// handling is needed here for the orchestrate path.
|
||||
core.setOutput('engineExitCode', exitCode);
|
||||
if (exitCode !== 0) {
|
||||
core.setFailed(`Build failed with exit code ${exitCode}`);
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -106,4 +106,274 @@ describe('buildCliArgs', () => {
|
||||
|
||||
expect(args).toStrictEqual(['build', '--targetPlatform=StandaloneLinux64']);
|
||||
});
|
||||
|
||||
describe('providerStrategy=local (default) regression', () => {
|
||||
// A full, representative sweep of every carried-forward `build` flag,
|
||||
// asserted byte-identical to what the pre-local-system implementation
|
||||
// produced. If this ever fails, the local/default branch changed -
|
||||
// which it must not, since local-system is meant to be strictly
|
||||
// additive.
|
||||
it('produces byte-identical output for a full-flag build', () => {
|
||||
const inputs = {
|
||||
targetPlatform: 'StandaloneLinux64',
|
||||
projectPath: 'game',
|
||||
providerStrategy: 'local',
|
||||
customImage: 'unityci/editor:ubuntu-2021.3.1f1',
|
||||
buildProfile: 'Assets/Profile.asset',
|
||||
buildName: 'MyGame',
|
||||
buildsPath: 'build',
|
||||
buildMethod: 'Foo.Bar',
|
||||
customParameters: '-profile SomeProfile -someBoolean',
|
||||
versioning: 'Tag',
|
||||
version: '1.2.3',
|
||||
androidVersionCode: '7',
|
||||
androidExportType: 'androidAppBundle',
|
||||
androidKeystoreName: 'keystore.keystore',
|
||||
androidKeystoreBase64: 'base64==',
|
||||
androidKeystorePass: 'keystore-secret',
|
||||
androidKeyaliasName: 'my-alias',
|
||||
androidKeyaliasPass: 'alias-secret',
|
||||
androidTargetSdkVersion: '33',
|
||||
androidSymbolType: 'public',
|
||||
sshAgent: '/tmp/ssh-agent.sock',
|
||||
sshPublicKeysDirectoryPath: '/tmp/keys',
|
||||
gitPrivateToken: 'ghp_token',
|
||||
chownFilesTo: '1000:1000',
|
||||
dockerCpuLimit: '4',
|
||||
dockerMemoryLimit: '4g',
|
||||
dockerIsolationMode: 'process',
|
||||
containerRegistryRepository: 'unityci/editor',
|
||||
containerRegistryImageVersion: '3',
|
||||
unityHubVersionOnMac: '3.4.0',
|
||||
unityLicensingServer: 'http://license.example.com',
|
||||
dockerWorkspacePath: '/github/workspace',
|
||||
manualExit: 'true',
|
||||
enableGpu: 'true',
|
||||
useHostNetwork: 'true',
|
||||
runAsHostUser: 'true',
|
||||
allowDirtyBuild: 'true',
|
||||
cacheUnityInstallationOnMac: 'true',
|
||||
skipActivation: 'true',
|
||||
linux64RemoveExecutableExtension: 'true',
|
||||
};
|
||||
|
||||
expect(buildCliArgs(inputsOf(inputs))).toStrictEqual([
|
||||
'build',
|
||||
'game',
|
||||
'--targetPlatform=StandaloneLinux64',
|
||||
'--customImage=unityci/editor:ubuntu-2021.3.1f1',
|
||||
'--buildProfile=Assets/Profile.asset',
|
||||
'--buildName=MyGame',
|
||||
'--buildsPath=build',
|
||||
'--buildMethod=Foo.Bar',
|
||||
'--customParameters=-profile SomeProfile -someBoolean',
|
||||
'--versioningStrategy=Tag',
|
||||
'--version=1.2.3',
|
||||
'--androidVersionCode=7',
|
||||
'--androidExportType=androidAppBundle',
|
||||
'--androidKeystoreName=keystore.keystore',
|
||||
'--androidKeystoreBase64=base64==',
|
||||
'--androidKeystorePassword=keystore-secret',
|
||||
'--androidKeyAlias=my-alias',
|
||||
'--androidKeyAliasPassword=alias-secret',
|
||||
'--androidTargetSdkVersion=33',
|
||||
'--androidSymbolType=public',
|
||||
'--sshAgent=/tmp/ssh-agent.sock',
|
||||
'--sshPublicKeysDirectoryPath=/tmp/keys',
|
||||
'--gitPrivateToken=ghp_token',
|
||||
'--chownFilesTo=1000:1000',
|
||||
'--dockerCpuLimit=4',
|
||||
'--dockerMemoryLimit=4g',
|
||||
'--dockerIsolationMode=process',
|
||||
'--containerRegistryRepository=unityci/editor',
|
||||
'--containerRegistryImageVersion=3',
|
||||
'--unityHubVersionOnMac=3.4.0',
|
||||
'--unityLicensingServer=http://license.example.com',
|
||||
'--dockerWorkspacePath=/github/workspace',
|
||||
'--manualExit',
|
||||
'--enableGpu',
|
||||
'--useHostNetwork',
|
||||
'--runAsHostUser',
|
||||
'--allowDirtyBuild',
|
||||
'--cacheUnityInstallationOnMac',
|
||||
'--skipActivation',
|
||||
'--linux64RemoveExecutableExtension',
|
||||
]);
|
||||
});
|
||||
|
||||
it('produces byte-identical output when providerStrategy is left unset (default)', () => {
|
||||
expect(
|
||||
buildCliArgs(inputsOf({ targetPlatform: 'StandaloneLinux64', buildName: 'MyGame' })),
|
||||
).toStrictEqual(['build', '--targetPlatform=StandaloneLinux64', '--buildName=MyGame']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('providerStrategy=local-system', () => {
|
||||
it('shells out to `orchestrate` with --providerStrategy=local-system', () => {
|
||||
const args = buildCliArgs(
|
||||
inputsOf({ targetPlatform: 'StandaloneLinux64', providerStrategy: 'local-system' }),
|
||||
);
|
||||
|
||||
expect(args).toStrictEqual([
|
||||
'orchestrate',
|
||||
'--targetPlatform=StandaloneLinux64',
|
||||
'--providerStrategy=local-system',
|
||||
]);
|
||||
});
|
||||
|
||||
it('still requires targetPlatform', () => {
|
||||
expect(() => buildCliArgs(inputsOf({ providerStrategy: 'local-system' }))).toThrow(
|
||||
/targetPlatform/,
|
||||
);
|
||||
});
|
||||
|
||||
it('puts projectPath as the positional argument right after "orchestrate", matching the build branch', () => {
|
||||
const args = buildCliArgs(
|
||||
inputsOf({
|
||||
targetPlatform: 'StandaloneLinux64',
|
||||
providerStrategy: 'local-system',
|
||||
projectPath: 'game',
|
||||
}),
|
||||
);
|
||||
|
||||
expect(args).toStrictEqual([
|
||||
'orchestrate',
|
||||
'game',
|
||||
'--targetPlatform=StandaloneLinux64',
|
||||
'--providerStrategy=local-system',
|
||||
]);
|
||||
});
|
||||
|
||||
it('carries forward every verified-supported flag', () => {
|
||||
const inputs = {
|
||||
targetPlatform: 'StandaloneLinux64',
|
||||
providerStrategy: 'local-system',
|
||||
buildName: 'MyGame',
|
||||
buildsPath: 'build',
|
||||
buildMethod: 'Foo.Bar',
|
||||
buildProfile: 'Assets/Profile.asset',
|
||||
androidVersionCode: '7',
|
||||
chownFilesTo: '1000:1000',
|
||||
sshAgent: '/tmp/ssh-agent.sock',
|
||||
sshPublicKeysDirectoryPath: '/tmp/keys',
|
||||
gitPrivateToken: 'ghp_token',
|
||||
manualExit: 'true',
|
||||
allowDirtyBuild: 'true',
|
||||
skipActivation: 'true',
|
||||
engineLaunchWrapper: 'flock /tmp/engine.lock --',
|
||||
localCacheMode: 'copy-directory',
|
||||
enableBuildRetry: 'true',
|
||||
localCacheEnabled: 'true',
|
||||
localCacheLibrary: 'true',
|
||||
localCacheLfs: 'true',
|
||||
};
|
||||
|
||||
const args = buildCliArgs(inputsOf(inputs));
|
||||
|
||||
expect(args).toContain('--buildName=MyGame');
|
||||
expect(args).toContain('--buildsPath=build');
|
||||
expect(args).toContain('--buildMethod=Foo.Bar');
|
||||
expect(args).toContain('--buildProfile=Assets/Profile.asset');
|
||||
expect(args).toContain('--androidVersionCode=7');
|
||||
expect(args).toContain('--chownFilesTo=1000:1000');
|
||||
expect(args).toContain('--sshAgent=/tmp/ssh-agent.sock');
|
||||
expect(args).toContain('--sshPublicKeysDirectoryPath=/tmp/keys');
|
||||
expect(args).toContain('--gitPrivateToken=ghp_token');
|
||||
expect(args).toContain('--manualExit');
|
||||
expect(args).toContain('--allowDirtyBuild');
|
||||
expect(args).toContain('--skipActivation');
|
||||
expect(args).toContain('--engineLaunchWrapper=flock /tmp/engine.lock --');
|
||||
expect(args).toContain('--localCacheMode=copy-directory');
|
||||
expect(args).toContain('--enableBuildRetry');
|
||||
expect(args).toContain('--localCacheEnabled');
|
||||
expect(args).toContain('--localCacheLibrary');
|
||||
expect(args).toContain('--localCacheLfs');
|
||||
});
|
||||
|
||||
it('never emits build-only/Docker-only flags that have no orchestrate-side equivalent', () => {
|
||||
const inputs = {
|
||||
targetPlatform: 'StandaloneLinux64',
|
||||
providerStrategy: 'local-system',
|
||||
customImage: 'unityci/editor:ubuntu-2021.3.1f1',
|
||||
customParameters: '-profile SomeProfile',
|
||||
versioning: 'Tag',
|
||||
version: '1.2.3',
|
||||
androidExportType: 'androidAppBundle',
|
||||
androidKeystoreName: 'keystore.keystore',
|
||||
androidKeystoreBase64: 'base64==',
|
||||
androidKeystorePass: 'keystore-secret',
|
||||
androidKeyaliasName: 'my-alias',
|
||||
androidKeyaliasPass: 'alias-secret',
|
||||
androidTargetSdkVersion: '33',
|
||||
androidSymbolType: 'public',
|
||||
dockerCpuLimit: '4',
|
||||
dockerMemoryLimit: '4g',
|
||||
dockerIsolationMode: 'process',
|
||||
containerRegistryRepository: 'unityci/editor',
|
||||
containerRegistryImageVersion: '3',
|
||||
unityHubVersionOnMac: '3.4.0',
|
||||
unityLicensingServer: 'http://license.example.com',
|
||||
dockerWorkspacePath: '/github/workspace',
|
||||
enableGpu: 'true',
|
||||
useHostNetwork: 'true',
|
||||
runAsHostUser: 'true',
|
||||
cacheUnityInstallationOnMac: 'true',
|
||||
linux64RemoveExecutableExtension: 'true',
|
||||
};
|
||||
|
||||
const args = buildCliArgs(inputsOf(inputs));
|
||||
|
||||
const excludedFlags = [
|
||||
'customImage',
|
||||
'customParameters',
|
||||
'versioning',
|
||||
'versioningStrategy',
|
||||
'version',
|
||||
'androidExportType',
|
||||
'androidKeystoreName',
|
||||
'androidKeystoreBase64',
|
||||
'androidKeystorePassword',
|
||||
'androidKeyAlias',
|
||||
'androidKeyAliasPassword',
|
||||
'androidTargetSdkVersion',
|
||||
'androidSymbolType',
|
||||
'dockerCpuLimit',
|
||||
'dockerMemoryLimit',
|
||||
'dockerIsolationMode',
|
||||
'containerRegistryRepository',
|
||||
'containerRegistryImageVersion',
|
||||
'unityHubVersionOnMac',
|
||||
'unityLicensingServer',
|
||||
'dockerWorkspacePath',
|
||||
'enableGpu',
|
||||
'useHostNetwork',
|
||||
'runAsHostUser',
|
||||
'cacheUnityInstallationOnMac',
|
||||
'linux64RemoveExecutableExtension',
|
||||
];
|
||||
|
||||
for (const flag of excludedFlags) {
|
||||
expect(args.some((arg) => arg === `--${flag}` || arg.startsWith(`--${flag}=`))).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('omits the new orchestrator-only flags when their inputs are unset', () => {
|
||||
const args = buildCliArgs(
|
||||
inputsOf({ targetPlatform: 'StandaloneLinux64', providerStrategy: 'local-system' }),
|
||||
);
|
||||
|
||||
expect(args.some((arg) => arg.startsWith('--engineLaunchWrapper='))).toBe(false);
|
||||
expect(args.some((arg) => arg.startsWith('--localCacheMode='))).toBe(false);
|
||||
expect(args).not.toContain('--enableBuildRetry');
|
||||
expect(args).not.toContain('--localCacheEnabled');
|
||||
expect(args).not.toContain('--localCacheLibrary');
|
||||
expect(args).not.toContain('--localCacheLfs');
|
||||
});
|
||||
});
|
||||
|
||||
it('still throws for a non-local/non-local-system providerStrategy', () => {
|
||||
expect(() =>
|
||||
buildCliArgs(inputsOf({ targetPlatform: 'StandaloneLinux64', providerStrategy: 'aws' })),
|
||||
).toThrow(/aws/);
|
||||
});
|
||||
});
|
||||
|
||||
+181
-26
@@ -1,16 +1,18 @@
|
||||
/**
|
||||
* Translates unity-builder's action inputs into `game-ci build` CLI flags.
|
||||
* Translates unity-builder's action inputs into `game-ci build` (or, for
|
||||
* providerStrategy=local-system, `game-ci orchestrate`) CLI flags.
|
||||
*
|
||||
* Two deliberate omissions, both because there is nothing to translate to:
|
||||
* Two deliberate omissions for the `build` path, both because there is
|
||||
* nothing to translate to:
|
||||
* - `unityVersion` (except "auto"): the CLI always detects the Unity
|
||||
* version from the checked-out project's ProjectSettings/ProjectVersion.txt
|
||||
* and has no flag to override that today (game-ci/cli's engine-detection
|
||||
* middleware unconditionally overwrites any passed value). Pinning a
|
||||
* version other than "auto" is a known, real gap versus the original
|
||||
* action - see the PR this shipped in.
|
||||
* - `providerStrategy` values other than "local": the base action (without
|
||||
* the separately-installed @game-ci/orchestrator plugin) already throws
|
||||
* for these today, so throwing here isn't a regression.
|
||||
* - `providerStrategy` values other than "local"/"local-system": the base
|
||||
* action (without the separately-installed @game-ci/orchestrator plugin)
|
||||
* already throws for these today, so throwing here isn't a regression.
|
||||
*
|
||||
* Boolean inputs use GitHub Actions' own truthy/falsy string convention
|
||||
* ('true'/'false', case-insensitive) - see actions/toolkit's getBooleanInput.
|
||||
@@ -61,15 +63,168 @@ const BOOLEAN_FLAGS: Array<[input: string, flag: string]> = [
|
||||
['linux64RemoveExecutableExtension', 'linux64RemoveExecutableExtension'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Flags carried forward into `game-ci orchestrate --providerStrategy=local-system`.
|
||||
*
|
||||
* Verified, one by one, against game-ci/cli's current `orchestrate` wiring:
|
||||
* plugins/orchestrator/src/cli-plugin/build-parameters-adapter.ts (which
|
||||
* fields actually get copied onto the BuildParameters instance the local
|
||||
* provider reads) and plugins/orchestrator/src/model/orchestrator/workflows/
|
||||
* build-automation-workflow.ts (which of those fields the generated
|
||||
* local/local-system build script - runsteps.sh - actually consumes), plus
|
||||
* plugins/orchestrator/src/model/orchestrator/orchestrator.ts and
|
||||
* .../options/orchestrator-folders.ts for the git-auth fields.
|
||||
*
|
||||
* Every `build`-only STRING_FLAGS/BOOLEAN_FLAGS entry NOT listed below was
|
||||
* deliberately excluded - see the per-field notes.
|
||||
*/
|
||||
const ORCHESTRATE_STRING_FLAGS: Array<[input: string, flag: string]> = [
|
||||
// build-automation-workflow.ts's runsteps.sh export block: BUILD_NAME,
|
||||
// BUILD_METHOD, BUILD_PROFILE, CHOWN_FILES_TO, ANDROID_VERSION_CODE.
|
||||
['buildName', 'buildName'],
|
||||
['buildsPath', 'buildsPath'],
|
||||
['buildMethod', 'buildMethod'],
|
||||
['buildProfile', 'buildProfile'],
|
||||
['androidVersionCode', 'androidVersionCode'],
|
||||
['chownFilesTo', 'chownFilesTo'],
|
||||
// Git-auth fields consumed by orchestrator.ts / orchestrator-folders.ts
|
||||
// for the repo clone step, independent of provider/Docker.
|
||||
['sshAgent', 'sshAgent'],
|
||||
['sshPublicKeysDirectoryPath', 'sshPublicKeysDirectoryPath'],
|
||||
['gitPrivateToken', 'gitPrivateToken'],
|
||||
|
||||
// --- Excluded, with reasons ---
|
||||
// customImage: build-parameters-adapter.ts assigns bp.customImage, but no
|
||||
// local/local-system codepath (provider or workflow) ever reads it back -
|
||||
// it is a Docker image selector with nothing to select on bare host.
|
||||
// customParameters: NOT assigned by build-parameters-adapter.ts at all
|
||||
// (unlike `build`'s CUSTOM_PARAMETERS env var). It only appears in the
|
||||
// unrelated hot-runner-service.ts path. Currently a no-op for
|
||||
// local-system, so intentionally not carried forward.
|
||||
// versioning / version: the adapter has no `versioningStrategy` concept -
|
||||
// it only accepts an already-resolved `buildVersion` string
|
||||
// (`bp.buildVersion = options.buildVersion || '0.0.1'`), which is a
|
||||
// different contract than this action's "Semantic/Tag/Custom strategy
|
||||
// name" `versioning` input. No existing action input maps cleanly onto
|
||||
// `--buildVersion`, so both are left out pending a real answer upstream.
|
||||
// androidExportType/androidKeystoreName/androidKeystoreBase64/
|
||||
// androidKeystorePass/androidKeyaliasName/androidKeyaliasPass/
|
||||
// androidTargetSdkVersion/androidSymbolType: none of these are assigned
|
||||
// by build-parameters-adapter.ts - only androidVersionCode is. Android
|
||||
// signing/export beyond the version code is currently unsupported by
|
||||
// `orchestrate`.
|
||||
// dockerCpuLimit/dockerMemoryLimit/dockerIsolationMode/
|
||||
// containerRegistryRepository/containerRegistryImageVersion/
|
||||
// dockerWorkspacePath: Docker container concepts with no bare-host
|
||||
// equivalent (containerRegistry* aren't even assigned by the adapter).
|
||||
// unityHubVersionOnMac: not assigned by the adapter at all.
|
||||
// unityLicensingServer: per the adapter's own comment, this "flows
|
||||
// opaquely through BuildParameters' index signature ... orchestrator
|
||||
// does not read them" - i.e. it is a no-op for `orchestrate` today;
|
||||
// licensing-server activation is `game-ci activate`'s concern, out of
|
||||
// scope here (matches this file's existing unityVersion/activation
|
||||
// scope boundary).
|
||||
];
|
||||
|
||||
const ORCHESTRATE_BOOLEAN_FLAGS: Array<[input: string, flag: string]> = [
|
||||
// build-automation-workflow.ts's runsteps.sh export block: MANUAL_EXIT.
|
||||
['manualExit', 'manualExit'],
|
||||
// pre-build-cleanup-service.ts reads this for the dirty-branch check,
|
||||
// independent of provider.
|
||||
['allowDirtyBuild', 'allowDirtyBuild'],
|
||||
// Explicitly documented upstream (orchestrator-options-plugin.ts,
|
||||
// build-parameters-adapter.ts) as "only meaningful for
|
||||
// providerStrategy=local(-system)", and exported as SKIP_ACTIVATION in
|
||||
// runsteps.sh.
|
||||
['skipActivation', 'skipActivation'],
|
||||
|
||||
// --- Excluded, with reasons ---
|
||||
// enableGpu: not assigned anywhere in build-parameters-adapter.ts or the
|
||||
// orchestrator model - a real, currently-unfilled gap versus `build`'s
|
||||
// GPU passthrough, not something to silently pretend to support.
|
||||
// useHostNetwork/runAsHostUser: Docker networking/uid-mapping concepts;
|
||||
// not assigned by the adapter, and runAsHostUser is meaningless by
|
||||
// construction on a bare host process that already runs as that host
|
||||
// user.
|
||||
// cacheUnityInstallationOnMac: build-parameters-adapter.ts DOES assign
|
||||
// bp.cacheUnityInstallationOnMac, but nothing downstream (no provider,
|
||||
// no workflow) ever reads it back - it's a currently-dead field for
|
||||
// `orchestrate`, so it is not carried forward despite being Mac-native
|
||||
// (i.e. not actually Docker-only) in principle.
|
||||
// linux64RemoveExecutableExtension: not assigned by the adapter at all.
|
||||
];
|
||||
|
||||
/**
|
||||
* New orchestrator-only inputs surfaced for providerStrategy=local-system.
|
||||
* All four are confirmed both registered as `orchestrate` CLI options
|
||||
* (orchestrator-options-plugin.ts) and consumed by
|
||||
* build-parameters-adapter.ts. `middlewarePipeline` is available in the same
|
||||
* places but deliberately deferred - its expected value shape is not yet
|
||||
* documented/stable enough to lock into this action's public input surface.
|
||||
*/
|
||||
const ORCHESTRATE_ONLY_STRING_FLAGS: Array<[input: string, flag: string]> = [
|
||||
['engineLaunchWrapper', 'engineLaunchWrapper'],
|
||||
['localCacheMode', 'localCacheMode'],
|
||||
];
|
||||
|
||||
const ORCHESTRATE_ONLY_BOOLEAN_FLAGS: Array<[input: string, flag: string]> = [
|
||||
['enableBuildRetry', 'enableBuildRetry'],
|
||||
['localCacheEnabled', 'localCacheEnabled'],
|
||||
['localCacheLibrary', 'localCacheLibrary'],
|
||||
['localCacheLfs', 'localCacheLfs'],
|
||||
];
|
||||
|
||||
function isTruthy(value: string): boolean {
|
||||
return value.trim().toLowerCase() === 'true';
|
||||
}
|
||||
|
||||
function pushStringFlags(
|
||||
args: string[],
|
||||
getInput: (name: string) => string,
|
||||
flags: Array<[input: string, flag: string]>,
|
||||
) {
|
||||
for (const [input, flag] of flags) {
|
||||
const value = getInput(input);
|
||||
// "--flag value" as two argv tokens is ambiguous when value itself
|
||||
// starts with "-" (e.g. customParameters="-profile Foo -someBoolean"):
|
||||
// yargs sees the next token starting with "-" and assumes the flag
|
||||
// takes no value, leaving the value string to be mis-parsed as its own
|
||||
// (partly alias-colliding) short-flag cluster. "--flag=value" glues
|
||||
// them into one token, which is unambiguous.
|
||||
if (value) args.push(`--${flag}=${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
function pushBooleanFlags(
|
||||
args: string[],
|
||||
getInput: (name: string) => string,
|
||||
flags: Array<[input: string, flag: string]>,
|
||||
) {
|
||||
for (const [input, flag] of flags) {
|
||||
const value = getInput(input);
|
||||
if (value && isTruthy(value)) args.push(`--${flag}`);
|
||||
}
|
||||
}
|
||||
|
||||
export interface BuildArgsOptions {
|
||||
getInput(name: string): string;
|
||||
}
|
||||
|
||||
export function buildCliArgs({ getInput }: BuildArgsOptions): string[] {
|
||||
const providerStrategy = getInput('providerStrategy') || 'local';
|
||||
|
||||
if (providerStrategy === 'local-system') {
|
||||
return buildOrchestrateArgs(getInput);
|
||||
}
|
||||
|
||||
if (providerStrategy !== 'local') {
|
||||
throw new Error(
|
||||
`Provider strategy "${providerStrategy}" is not supported by this thin wrapper. ` +
|
||||
"Use providerStrategy=local, or invoke game-ci/cli's `orchestrate` command directly " +
|
||||
'for remote builds.',
|
||||
);
|
||||
}
|
||||
|
||||
const args: string[] = ['build'];
|
||||
|
||||
const projectPath = getInput('projectPath');
|
||||
@@ -81,30 +236,30 @@ export function buildCliArgs({ getInput }: BuildArgsOptions): string[] {
|
||||
}
|
||||
args.push(`--targetPlatform=${targetPlatform}`);
|
||||
|
||||
const providerStrategy = getInput('providerStrategy') || 'local';
|
||||
if (providerStrategy !== 'local') {
|
||||
throw new Error(
|
||||
`Provider strategy "${providerStrategy}" is not supported by this thin wrapper. ` +
|
||||
"Use providerStrategy=local, or invoke game-ci/cli's `orchestrate` command directly " +
|
||||
'for remote builds.',
|
||||
);
|
||||
pushStringFlags(args, getInput, STRING_FLAGS);
|
||||
pushBooleanFlags(args, getInput, BOOLEAN_FLAGS);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
function buildOrchestrateArgs(getInput: (name: string) => string): string[] {
|
||||
const args: string[] = ['orchestrate'];
|
||||
|
||||
const projectPath = getInput('projectPath');
|
||||
if (projectPath) args.push(projectPath);
|
||||
|
||||
const targetPlatform = getInput('targetPlatform');
|
||||
if (!targetPlatform) {
|
||||
throw new Error('targetPlatform is required.');
|
||||
}
|
||||
args.push(`--targetPlatform=${targetPlatform}`);
|
||||
|
||||
for (const [input, flag] of STRING_FLAGS) {
|
||||
const value = getInput(input);
|
||||
// "--flag value" as two argv tokens is ambiguous when value itself
|
||||
// starts with "-" (e.g. customParameters="-profile Foo -someBoolean"):
|
||||
// yargs sees the next token starting with "-" and assumes the flag
|
||||
// takes no value, leaving the value string to be mis-parsed as its own
|
||||
// (partly alias-colliding) short-flag cluster. "--flag=value" glues
|
||||
// them into one token, which is unambiguous.
|
||||
if (value) args.push(`--${flag}=${value}`);
|
||||
}
|
||||
args.push('--providerStrategy=local-system');
|
||||
|
||||
for (const [input, flag] of BOOLEAN_FLAGS) {
|
||||
const value = getInput(input);
|
||||
if (value && isTruthy(value)) args.push(`--${flag}`);
|
||||
}
|
||||
pushStringFlags(args, getInput, ORCHESTRATE_STRING_FLAGS);
|
||||
pushStringFlags(args, getInput, ORCHESTRATE_ONLY_STRING_FLAGS);
|
||||
pushBooleanFlags(args, getInput, ORCHESTRATE_BOOLEAN_FLAGS);
|
||||
pushBooleanFlags(args, getInput, ORCHESTRATE_ONLY_BOOLEAN_FLAGS);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
+5
-2
@@ -43,8 +43,11 @@ export async function run() {
|
||||
const exitCode = await exec.exec(cliPath, args, { ignoreReturnCode: true });
|
||||
|
||||
// Matches the original action's engineExitCode output: 0 on success,
|
||||
// otherwise the exit code of whichever step (activation or build)
|
||||
// failed - which is exactly what the CLI subprocess itself exits with.
|
||||
// otherwise the exit code of whichever step (activation or build) - or,
|
||||
// for providerStrategy=local-system, whichever stage of the
|
||||
// orchestrator's setup/build/cleanup workflow - failed. Either way it's
|
||||
// exactly what the CLI subprocess itself exits with, so no special
|
||||
// handling is needed here for the orchestrate path.
|
||||
core.setOutput('engineExitCode', exitCode);
|
||||
|
||||
if (exitCode !== 0) {
|
||||
|
||||
Reference in New Issue
Block a user