Skip to content

feat: allow every CLI option to be set via a GAME_CI_* env var - #262

Merged
frostebite merged 1 commit into
mainfrom
feat/game-ci-env-prefix
Sep 10, 2026
Merged

feat: allow every CLI option to be set via a GAME_CI_* env var#262
frostebite merged 1 commit into
mainfrom
feat/game-ci-env-prefix

Conversation

@frostebite

Copy link
Copy Markdown
Member

Why

Every new CLI option currently needs a matching input added to — and a release cut for — each thin wrapper (unity-builder, unity-test-runner, unity-activate) before anyone can actually use it from a workflow. --dockerEnv (#261) is the most recent example: shipped in the CLI, unusable from a workflow until three more PRs land.

That per-wrapper PR treadmill is the thing this removes.

Each wrapper spawns the CLI as a host child process, which inherits the workflow environment — the wrappers already rely on exactly this for credentials:

Unity credentials (UNITY_EMAIL, UNITY_PASSWORD, ...) are read by the CLI itself from its own process environment
unity-activate/src/index.ts

This generalises that already-working mechanism from credentials to every option.

What

.env("GAME_CI") — every option is also settable as GAME_CI_<SCREAMING_SNAKE_CASE>:

- uses: game-ci/unity-builder@v6
  env:
    GAME_CI_DOCKER_MEMORY_LIMIT: 14g
    GAME_CI_DOCKER_ENV: |
      IL2CPP_ADDITIONAL_ARGS=--maxcpucount=2

No wrapper change needed — now or for any future option.

On the comment this replaces

src/cli.ts carried a deliberate note against using .env(). That note is correct, and I verified it rather than assuming — a blanket .env() really does fail under strict(true):

Unknown arguments: ACSetupSvcPort, allusersprofile, appdata, baggage, chromeCrashpadPipeName, ...

But its objection is specific to the unprefixed form. .env(prefix) only maps vars carrying the prefix, so unrelated vars are never considered. This isn't overturning that decision — it's the option the decision never considered.

Verified against the real parser configuration (strip-dashed, dot-notation: false, etc.), not just a synthetic reproduction.

Precedence

explicit arg > GAME_CI_* env > option default

A wrapper passing an explicit flag still wins; the environment only fills what it left unset. The unprefixed credential fallbacks (UNITY_EMAIL etc. in unity-options.ts) are long-standing public contract and are unchanged — this is a superset, not a replacement.

Tradeoff

GAME_CI_* is now a reserved namespace: a GAME_CI_ var matching no option is a hard failure rather than being ignored. That's deliberate — a typo'd GAME_CI_DOCKER_MEMORY_LIMT should tell you, not silently do nothing.

Tests

5 tests in src/cli.test.ts (24 pass / 0 fail): prefix mapping, arg-beats-env precedence, non-prefixed vars ignored, unprefixed UNITY_EMAIL still working, and unknown-prefixed-var rejection.

That last one is asserted out-of-process — strict failures route through Cli.handleFailure, which process.exit(1)s, so in-process it takes the test runner down with it.

Full-suite check: 1234 pass / 246 fail on this branch vs 1230 pass / 246 fail on untouched main — identical failure count, +4 from this PR's new tests. The 246 are pre-existing and unrelated.

🤖 Generated with Claude Code

Each thin wrapper (unity-builder, unity-test-runner, unity-activate)
spawns this CLI as a host child process, which inherits the workflow
environment. Mapping GAME_CI_<SCREAMING_SNAKE_CASE> onto options means a
workflow `env:` block can reach any option the wrapper's action.yml has
no input for - so a new option here is usable from workflows the day it
ships, without a PR and release against every wrapper first.

A blanket .env() was previously avoided for a real reason: under
strict(true) it maps every process env var to an option name and then
rejects the invocation wholesale ("Unknown arguments: allusersprofile,
appdata, ..."). That objection is specific to the unprefixed form.
.env(prefix) only maps vars carrying the prefix, so unrelated
environment variables are never considered - verified against the real
parser configuration, not just a synthetic one.

Precedence is arg > GAME_CI_* env > option default, so a wrapper passing
an explicit flag still wins and the environment only fills what it left
unset. The unprefixed fallbacks that secret-bearing options set in their
own .option() default (UNITY_EMAIL etc.) are long-standing public
contract and are unchanged - this is a superset, not a replacement.

Tradeoff: GAME_CI_* is now a reserved namespace. A GAME_CI_ var matching
no option is a hard failure rather than being ignored, which surfaces
typos instead of silently dropping them.

Co-Authored-By: Claude Opus 5 <[email protected]>
@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 39 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: c922844c-8563-432a-a9ce-43b6c6e77442

📥 Commits

Reviewing files that changed from the base of the PR and between d003d02 and 0c563ef.

📒 Files selected for processing (2)
  • src/cli.test.ts
  • src/cli.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

frostebite added a commit to game-ci/documentation that referenced this pull request Sep 10, 2026
The "environment variables don't reach Unity" section previously offered
customParameters as the only workaround. That is still the right answer
for Unity command line arguments, but it cannot set an environment
variable - which is exactly what Unity's own IL2CPP_ADDITIONAL_ARGS and
similar toolchain knobs read. dockerEnv (game-ci/cli#261) closes that
gap, so lead with it and keep customParameters as the argument-passing
alternative, with a note on when each applies.

Also documents the GAME_CI_* prefix (game-ci/cli#262): every CLI option
is settable as an environment variable, which is how a workflow reaches
options the action has no matching input for. Records the precedence
(input > env > default) and the reserved-namespace tradeoff.

Cross-reference anchors verified against the built HTML rather than
assumed.

Co-Authored-By: Claude Opus 5 <[email protected]>
@frostebite
frostebite merged commit 1b44e41 into main Sep 10, 2026
22 checks passed
@frostebite
frostebite deleted the feat/game-ci-env-prefix branch September 10, 2026 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant