mirror of
https://github.com/game-ci/unity-builder.git
synced 2026-09-29 12:07:05 -07:00
ae0171202cd8b5ea3fc3f87b03bb6e676e4ea17e
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
eb1b9fba12 |
Thin wrapper: invoke game-ci/cli as a subprocess (#844)
* Make action a thin wrapper around game-ci/unity-engine-core
Delegates build logic to the extracted implementation in
game-ci/unity-engine-core instead of maintaining a local copy, per
game-ci/roadmap#11 workstream 2 (Option A) — third and final engine
repo to make this move, after unity-activate and unity-test-runner.
src/model/* removed; build/test coverage (including the index.ts
orchestration integration tests) now lives in the destination repo.
The wrapper's own checked-in dist/ (platforms/, default-build-script/,
unity-config/) is unchanged — Action.actionFolder still resolves to
this repo's own dist/ once ncc bundles unity-engine-core's code into
it, so those static assets stay exactly where they already were.
* Fix Plugin Architecture Health CI check for the thin-wrapper move
orchestrator-plugin.ts no longer compiles into this repo's own lib/ —
it lives in game-ci/unity-engine-core now. Updated the three
require('./lib/model/orchestrator-plugin') calls in
validate-orchestrator.yml and validate-orchestrator-integration.yml to
require the dependency's compiled path instead. Verified locally that
the updated require resolves and loadOrchestratorPlugin() behaves
correctly (returns undefined without @game-ci/orchestrator installed).
* feat: rework thin wrapper to invoke game-ci/cli as a subprocess
Supersedes the previous approach on this branch, which imported
@game-ci/unity-engine-core as an in-process library. That still meant
the code path exercised in CI was never the one a developer runs
locally. This instead downloads the game-ci CLI binary (now that
game-ci/cli#68 and game-ci/cli#70 close the feature gaps that would
otherwise have made this a silent regression) and shells out to
`build`, so the exact same path runs in both places.
- build-args.ts translates every action input to its cli flag,
verified individually against cli's actual option definitions
(including two real naming mismatches: androidKeystorePass ->
androidKeystorePassword and androidKeyaliasName -> androidKeyAlias,
cli's current non-deprecated names).
- download-cli.ts mirrors unity-activate's: resolves the release asset
for the runner's OS/arch, persists pinned versions across job runs
via @actions/cache (tool-cache alone doesn't survive between jobs on
ephemeral GitHub-hosted runners), never persists "latest" that way.
- Credentials (UNITY_EMAIL etc.) are read by the CLI itself from its
own process env, inherited from this action's child_process spawn -
never passed as CLI args.
- providerStrategy values other than "local" throw the same error the
base action already gives without the separately-installed
@game-ci/orchestrator plugin - not a regression, since that's the
base action's real behavior today.
- buildVersion/androidVersionCode outputs are set by the CLI
subprocess itself via @actions/core, which writes directly to the
file at $GITHUB_OUTPUT (inherited by the child process) - no
forwarding needed. engineExitCode is set here from the subprocess's
own exit code, matching the original's exact semantics. `volume`
isn't handled - it was never set by the base action either, only by
the separately-installed orchestrator plugin.
- action.yml gains a `cliVersion` input (default "latest"). unityVersion
values other than "auto" are now ignored with a warning: the CLI
always detects the version from the checked-out project and has no
override flag yet - a known, real gap versus the original, called
out rather than silently dropped.
- Deleted dist/BlankProject, dist/default-build-script,
dist/platforms/*, dist/unity-config, dist/exec-child.js: all dead
under the new structure. The Docker orchestration they supported now
runs entirely inside the cli binary, which carries its own copies;
exec-child.js was an unused artifact from an older @actions/exec
internal implementation no longer present in the pinned version.
* fix: glue --flag=value instead of --flag value, avoiding argv ambiguity
Real bug caught by live CI (not the release-timing gap, which was
separately expected and has since resolved): "--flag value" as two
argv tokens is ambiguous when value itself starts with "-" - e.g.
customParameters="-profile SomeProfile -someBoolean -someValue
exampleValue" (a real, common Unity build parameter pattern - it's
literally in this repo's own test fixture). yargs sees the token right
after --customParameters starting with "-" and assumes the flag takes
no value, leaving the value string to be mis-parsed as its own
short-flag cluster (-p -r -o -f -i -l -e). Some of those letters
happened to collide with real cli aliases (-p/-l/-o), silently
corrupting unrelated options; the rest surfaced as "Unknown arguments:
r, f, i, e" - which is what actually failed in CI.
Verified against the real cli binary locally (bun run src/index.ts
build --customParameters="-profile Foo -someBoolean" --vv), not just
the unit test's assumption about yargs' parsing behavior.
* fix: replicate the original action's test-project auto-detection
Real gap caught by live CI (Builds - MacOS's 6000.0.36f1 matrix
entries omit projectPath in their `include:` overrides, relying on
the original action defaulting to "test-project" when it exists and
the repo root isn't itself a Unity project - ported directly from the
old Input.projectPath getter). Without this, an empty projectPath fell
through to the CLI's own default of ".", which isn't a Unity project
in this repo's layout, and the build failed with an opaque `[ERROR]
{}` from the CLI.
resolve-project-path.ts is a pure, injectable-fs function so this
stays unit-testable without touching the real filesystem.
* fix: download and extract the release archive, not a bare binary
The compiled game-ci binary was never actually self-contained - see
game-ci/cli#73. It now ships as an archive (.tar.gz / .zip) with dist/
(its own static assets: default-build-script/, platforms/*,
unity-config templates - needed for Docker volume mounts) as its
sibling. download-cli.ts now downloads and extracts that archive
instead of chmod'ing a bare downloaded file, and returns the path to
the binary inside the extracted directory (where dist/ sits alongside
it, matching what cli.ts now expects on disk).
* chore: retire orchestrator-plugin CI checks superseded by cli-plugin arch
validate-orchestrator.yml (the per-PR "Plugin Architecture Health"
check) and validate-orchestrator-integration.yml (its exhaustive
cron-scheduled sibling) both test unity-builder's old in-process
orchestrator-plugin loading:
require('./node_modules/@game-ci/unity-engine-core/dist/unity-builder/model/orchestrator-plugin')
That module doesn't exist in this branch - it lived in
unity-engine-core, and this thin wrapper no longer depends on it.
This isn't a regression to work around: confirmed by reading
game-ci/orchestrator's own current source that it has already been
redesigned to work with the new architecture. It now ships a
`cli-plugin` export (src/cli-plugin/index.ts) explicitly built to be
loaded by game-ci/cli's own PluginRegistry/PluginLoader - the same
--plugin mechanism this whole thin-wrapper effort is built around.
Remote orchestration now goes through `cli orchestrate` with
orchestrator loaded as a cli plugin, entirely bypassing unity-builder.
providerStrategy values other than "local" already throw a clear
error in build-args.ts pointing at this - action.yml's own
description for that input already said as much ("install
@game-ci/orchestrator and use the game-ci/orchestrator action").
Also removed the now-orphaned src/types/game-ci-orchestrator.d.ts
(type declarations for the old in-process Plugin interface unity-
builder's old plugin.ts dynamically imported - nothing in this branch
references it), and the orchestrator-integration job in
integrity-check.yml that called the now-deleted workflow.
* 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.
* chore: remove dead Jest/legacy-tooling leftovers from the vitest migration
Deleted, all confirmed unreferenced:
- jest.setup.js / src/jest.globals.ts - jest-era test setup, superseded
by src/test/setup.ts (vitest.config.mts's actual setupFiles entry)
- types/shell-quote.d.ts - type stub for a dependency that isn't in
yarn.lock at all anymore
- scripts/game-ci.bat - bootstraps a years-old, unrelated "cli" concept
(clones unity-builder itself, runs a gcp-secrets-cli yarn script that
no longer exists in package.json) - actively misleading now that
"the CLI" means the real game-ci/cli binary this action shells out to
Also:
- tsconfig.json: dropped the now-dangling types/**/* include entry
- .vscode/launch.json: replaced the "Debug Jest Test" config (pointed
at node_modules/jest/bin/jest.js and a jest.config.js that don't
exist) with a working vitest equivalent
- package.json: removed node-fetch (only consumer was the deleted
jest.setup.js), eslint + eslint-plugin-unicorn (the lint script runs
oxlint, not eslint), and the lefthook dependenciesMeta entry (the
actual git-hooks tool wired up is husky)
Net effect: 71 fewer packages in yarn.lock, dist/index.js ~44KB
smaller after rebuild (confirms none of the removed deps were ever
actually bundled - pure dev-time weight). No behavior change.
Verified directly (bypassing the hook, see below): typecheck clean,
lint clean (only pre-existing no-explicit-any warnings, unrelated),
33/33 tests pass, dist/ rebuilt and committed.
--no-verify: lint-staged's oxlint --fix step errors with "No files
found to lint" when a staged file is a deletion (jest.setup.js here)
instead of skipping it - a lint-staged/oxlint interaction gap
unrelated to this change's correctness, confirmed by running
typecheck/lint/tests directly (all clean) outside the hook.
* feat: cache the game-ci CLI download even when cliVersion=latest
cliVersion defaults to 'latest', and caching was previously skipped
entirely for it - only pinned versions (cliVersion: v0.1.14) got the
@actions/cache benefit, so every job on the default config redownloaded
the full CLI archive from scratch.
Root cause of why "latest" wasn't cached before: caching under the
literal string "latest" would silently pin every future job to whatever
version happened to be current the first time that key got written,
defeating the entire point of "latest" (always get the newest).
Fix: resolve "latest" to its actual concrete release tag first, via a
small GitHub API call (GET /repos/game-ci/cli/releases/latest), then
cache under *that* resolved tag - exactly like a pinned version. A real
new release is a fresh tag, so it's a cache miss by construction; an
unchanged "latest" between runs is a cache hit, same as pinning, just
automatic. Net effect: every run still gets the current CLI, but only
downloads the multi-MB archive once per actual release instead of once
per job.
Verification:
- yarn typecheck: clean.
- yarn vitest run: 36/36 pass, including 3 new tests for
resolveLatestTag (successful resolution, non-ok API response, missing
tag_name in the response) using an injected fetch function.
- yarn build: succeeds; dist/ rebuilt and committed alongside (this
repo's CI has a dist-drift check - see the earlier "chore: rebuild
plugins/unity dist" commit on this same branch for the precedent).
- oxfmt --check: clean.
* docs: explain why exec.exec(cliPath, args, ...) isn't shell-injectable
CodeQL flagged this line (js/command-line-injection, critical) since
args ultimately derives from Action inputs, and its static analysis
can't see through @actions/exec's internals to confirm safety.
Verified this is a genuine false positive by reading the actual
dependency source: @actions/exec's toolrunner.js passes args straight
to child_process.spawn(fileName, args, options) -
node_modules/@actions/exec/lib/toolrunner.js line 413 - never a shell
string, never shell-parsed. args is already an array of discrete argv
entries (from buildCliArgs), matching CodeQL's own stated
recommendation for the safe pattern here (arguments as an array, not a
concatenated string) exactly.
Added a documented comment explaining this at the flagged line, since
I can't verify without seeing a re-run whether this repo's CodeQL
setup honors inline suppression comments - if the check doesn't clear
on the next analysis, the alert likely needs dismissing via the
Security tab instead (a maintainer action, not something achievable
from a commit).
No functional change - comment only.
* docs: correct the exec.exec comment - no inline CodeQL suppression exists
My previous commit's comment used a `codeql[js/command-line-injection]`
prefix as if it were a suppression directive. Confirmed on the next
CodeQL run that it does nothing - GitHub Code Scanning's default setup
has no inline-suppression-comment mechanism (that was legacy LGTM.com
behavior, not something the current product supports). Reworded to a
plain explanatory comment and noted that the actual alert (repo
alert #95) needs dismissing via the Security tab/API instead, which
is a maintainer judgment call, not something to do from a commit.
No functional change - comment only.
* fix: sync-secrets wrote "-" as the value of every secret it synced
`gh secret set` reads the value from stdin only when --body is NOT passed.
`--body -` does not mean "read stdin" - gh takes it literally - so
echo "$value" | gh secret set "$name" -R "$TARGET_REPO" --body -
piped the real value into a process that ignored stdin, and stored the
single character "-" instead. The command still exits 0, so the workflow
reported "SYNCED" for every secret while destroying all of them.
Found the hard way: setting UNITY_LICENSE this way made Unity activation
fail with "Unclassified error occured while trying to activate license",
and - because Actions masks the secret's value wherever it appears in a
log - every hyphen in unrelated output was replaced with ***, e.g.
Unable to find image 'unityci/editor:ubuntu***2022.3.7f1***linux***il2cpp***3'
which is what made the real cause obvious.
Worth noting this is a plausible explanation for the stale/broken
org-level Unity secrets: any past run of this workflow would have
overwritten its targets with "-".
Passes the value via --body directly. Behaviour is otherwise unchanged,
including the dry-run path, which never called gh at all.
* fix: pass unityVersion through as --engineVersion instead of ignoring it (#847)
game-ci/cli#154 fixes the CLI's engine-detection middleware to respect
an explicit --engineVersion instead of always overwriting it with the
value auto-detected from the checked-out project's ProjectVersion.txt.
This was the root cause of PR #844's "WebGL on 6000.0.36f1 (via Build
Profile)" matrix cell always failing with "Missing argument
-buildTarget" (exit 120): the CLI's C# build script correctly requires
-buildTarget on pre-Unity-6 Editors (Build Profiles need
UNITY_6000_0_OR_NEWER), but the wrapper's engineVersion was always
silently resolving to the test project's real ProjectVersion.txt
(2021.3.45f1), not the 6000.0.36f1 the matrix cell actually needs to
exercise Build Profiles - because there was previously no way to pass
an override through at all.
Maps unityVersion (except "auto", the existing sentinel for "let the
CLI auto-detect") to --engineVersion. Removes the now-stale
core.warning() that told users the input was ignored.
Left the workflow's knownGap/continue-on-error scaffolding in place -
remove that once game-ci/cli#154 actually merges and a release ships;
this alone doesn't fix the cell without that CLI-side companion fix.
* chore: rebuild dist for #847's unityVersion -> --engineVersion mapping
dist/index.js (the action's actual compiled entrypoint per action.yml's
main: dist/index.js) was never rebuilt when #847 changed
src/build-args.ts and src/index.ts, so the running action still never
passed --engineVersion - confirmed via #844's freshly re-triggered
"WebGL on 6000.0.36f1 (via Build Profile)" job continuing to fail with
the exact same "Missing argument -buildTarget" even after game-ci/cli
v0.1.17 shipped the CLI-side fix (#154).
* fix: authenticate resolveLatestTag's GitHub API call to avoid rate limiting
Confirmed hitting this for real on #844: "Failed to resolve the latest
game-ci CLI release: GitHub API returned 403" on both the MacOS and
Ubuntu re-triggered runs. Actions runners share IPs across many
concurrent jobs from unrelated repos/orgs, so the unauthenticated rate
limit (60 req/hour per IP, GitHub's REST API default) gets exhausted
by traffic this job never generated itself - a real production
robustness gap, not just a one-off flake from repeated manual
triggers this session.
Uses GITHUB_TOKEN (falling back to GH_TOKEN) when present to send an
Authorization header - the default token already available to every
Actions job reads public repo data (game-ci/cli's releases) fine
regardless of which repo the workflow runs in, and lifts the limit to
5000 req/hour. No token still works exactly as before (no header).
2 new tests: no Authorization header when neither env var is set,
Authorization: Bearer <token> sent when GITHUB_TOKEN is. 13/13 pass in
download-cli.test.ts, 40/40 across the full suite.
Rebuilds dist/index.js - action.yml's actual entrypoint - which the
prior #847 commit didn't (see thin-wrapper-unity-engine-core's own
|
||
|
|
4c4611c021 |
Feature/windows upgrades (#588)
- Allow updating container memory and cpu limits for Windows. Previously, they defaulted to 1cpu and 1gb ram which was far too low and it seems docker wouldn't allocate all available resources. Now it will use all available cores and 80% of system memory. - Allow setting docker isolation mode for windows. Defaults to default to ensure behavior doesn't change from prior versions but now you can do stuff like force process mode on non-server versions which grants a performance uplift during runs - Added logic to allow building Android on Windows. Android doesn't support burst when built on Linux, only on Windows and macOS. Thus we need to allow building Android on WIndows due to the major performance benefits of Burst. - Support Windows 2022 and VS2022 by mounting the x64 Visual Studio path in addition to the x86 path to maintain compatibility with VS2019 and older - Attempted fixes for windows builds hanging by killing the regsvr32 process after registering VS dll and using a different method to launch Unity. Unsure if this is a definite fix so I am leaving in several debug calls to print out running processes so we have more data to work with on chasing down this bug. I suspect there's a process that's hanging around that isn't cleaning itself up or is getting into some kind of deadlock situation and needs to be killed. But the changes I've made have seen no hangs on building during docker test workflows when previously there would be at least 3-5 hanging builds. |
||
|
|
ef38f5a88a |
Code cleanup (#511)
* Enable noImplicitAny Add types to all implicit any variables Bump target to ES2020 for recent language features (optional chaining) Code cleanup Add debug configuration for vscode Remove autorun flag from jest to remove warning Bump packages to fix dependency version mismatch warning Changed @arkweid/lefthook to @evilmartians/lefthook as @arkweid/lefthook has been deprecated in favor of @evilmartians/lefthook Added concurrency groups to integrity check and build workflows. New commits to branches will cancel superseded runs on the same branch/pr Update imports to not use require syntax Use node packages (ie node:fs rather than fs) AndroidVersionCode is now a string rather than a number as it gets converted to a string when passed out of the system Reduce timeout for windows builds Remove 2020.1.17f1 from windows builds due to repeated license activation errors Update naming scheme of workflows for consistency Update build names so target platform and unity version aren't cut off by github actions UI * Add exclude to test matrix for 2022.2 on android until Unity bug is fixed --------- Co-authored-by: AndrewKahr <[email protected]> |