The S3 deserialization issue was caused by @aws-sdk/client-s3 v3.1005
(schema-based AwsRestXmlProtocol), not LocalStack's version. The SDK
is now pinned to ~3.779.0 in the orchestrator repo, so localstack:latest
works correctly.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
localstack:latest (v4.14+) returns JSON responses for some S3 operations,
but @aws-sdk/client-s3 v3.779+ uses AwsRestXmlProtocol which expects XML.
This breaks all SharedWorkspaceLocking tests (locking, e2e caching,
retaining). Pin to v3.8.1 (last v3 release) where the S3 provider
returns proper XML responses.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add workflow_call trigger to validate-orchestrator-integration.yml
so other workflows can invoke the exhaustive test suite
- Add orchestrator-integration job to integrity-check.yml that runs
on pushes to main (skipped on PRs to avoid 1-2h CI time)
- Daily cron + manual dispatch remain as fallback triggers
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Verifies end-to-end that loadOrchestrator().run() is correctly wired
to Orchestrator.run(), BuildParameters.create() produces valid config,
and plugin services resolve to real implementations.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Previously both loadOrchestrator() and loadPluginServices() caught all
errors, masking real failures like syntax errors or missing transitive
dependencies. Now only MODULE_NOT_FOUND / ERR_MODULE_NOT_FOUND errors
are suppressed; all other exceptions are rethrown.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
The orchestrator is a plugin, not an enterprise feature. Renamed
loadEnterpriseServices -> loadPluginServices and all related variables,
types, log messages, and test descriptions to use "plugin" terminology.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Install scripts now live at game-ci/orchestrator where the CLI releases
are published. Removed from unity-builder to avoid duplication.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Ensure orchestrator validation runs when yarn.lock changes, since
dependency updates can affect plugin compatibility.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
The refactor/orchestrator-extraction branch was not matching the
feature/** pattern, preventing the integration workflow from running
after fix commits were pushed.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
The orchestrator tests need compiled output (dist/index.js) to exist
before running integration tests that spawn containers/k8s jobs.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add validate-orchestrator-integration.yml with 3 parallel jobs:
plugin-interface (unit tests + smoke tests), k8s-integration
(k3d + localstack), and aws-integration (localstack only)
- Add orchestrator-plugin.test.ts with 15 unit tests covering
loadOrchestrator() and loadEnterpriseServices() for both
installed and not-installed states
- Disk space management follows proven patterns from orchestrator
repo (parallel jobs, aggressive cleanup between tests)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
The orchestrator package brings eslint dependencies that conflict with
unity-builder's peer deps. Since this install is only for smoke-testing
the plugin loader, --legacy-peer-deps is safe here.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
The orchestrator job in integrity-check.yml called the deleted
orchestrator-integrity.yml workflow, causing CI failure.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Delete src/cli.ts, src/cli/ (commands, tests, input-mapper) — moved
to game-ci/orchestrator repo (PR #813 reference)
- Delete .github/workflows/release-cli.yml — moved to orchestrator
- Remove bin, pkg, yargs, @types/yargs, pkg from package.json
- Fix validate-orchestrator.yml:
- Build TypeScript before running require() smoke tests
- Remove || echo fallback that swallowed errors
- Add smoke test that installs orchestrator via npm pack and
verifies loadOrchestrator() returns defined exports
Legacy src/model/cli/ (Cli class, CliFunctionsRepository) preserved —
used by Input.getInput() and build-parameters.ts on main.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Remove the entire src/model/orchestrator/ directory (148 files, ~30k lines)
and refactor all dependent code to use the plugin loader pattern.
Key changes:
- build-parameters.ts: replace OrchestratorOptions with Input.getInput()
- input.ts: remove OrchestratorQueryOverride input source
- github.ts: strip to minimal class (only githubInputEnabled remains)
- cli/cli.ts: remove orchestrator CLI commands, simplify to core structure
- input-readers/*: replace OrchestratorSystem.Run with child_process.exec
- orchestrator-plugin.ts: import from @game-ci/orchestrator package
- orchestrate.ts, build.ts: use plugin loader instead of direct imports
- index.ts: inline SyncStrategy type, fix implicit any types
- Add type declarations for @game-ci/orchestrator
- Remove orchestrator-only npm dependencies (AWS SDK, K8s, etc.)
- Remove orchestrator-specific npm scripts and CI workflows
- Update validate-orchestrator.yml for external repo validation
All enterprise features gracefully degrade when @game-ci/orchestrator
is not installed — the plugin loader returns undefined and optional
chaining in index.ts skips all enterprise service calls.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace 8 direct orchestrator service imports with a thin plugin loader.
- loadOrchestrator(): loads remote build orchestration
- loadEnterpriseServices(): loads enterprise features for local builds
All functionality is preserved; only the import mechanism changes.
This is the first step toward making orchestrator an optional dependency.
Includes comprehensive integration tests for enterprise feature wiring
that verify gating logic, call ordering, and provider strategy routing.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Runs on PRs that touch orchestrator source or bridge files.
Validates:
- Orchestrator source files are in sync with standalone repo
- Bridge file exports exist in both repos
- Orchestrator tests pass in both unity-builder and standalone contexts
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Cache is an orchestrator feature, so it belongs under `game-ci orchestrate cache`
rather than as a top-level `game-ci cache` command.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
The test mock was missing gitAuthMode, causing useHeaderAuth to
default to true and strip the token from repo URLs. Adding
gitAuthMode: 'url' restores the expected URL-mode behavior.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Use the Checks API to flip failed macOS build conclusions to neutral
(gray dash) so unstable builds don't show red X marks on PRs.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add three test files covering the two highest-priority gaps in PR #777:
1. src/index-enterprise-features.test.ts (21 tests) - Integration wiring
tests for index.ts that verify conditional gating of all enterprise
services (GitHooks, LocalCache, ChildWorkspace, SubmoduleProfile,
LfsAgent). Tests that disabled features (default) are never invoked,
enabled features call the correct service methods, and the order of
operations is correct (restore before build, save after build).
Also tests non-local provider strategy skips all enterprise features.
2. src/model/enterprise-inputs.test.ts (103 tests) - Input/BuildParameters
wiring tests for all 20 new enterprise properties. Covers defaults,
explicit values, and boolean string parsing edge cases (the #1 source
of bugs: 'false' as truthy, 'TRUE' case sensitivity, '1', 'yes').
Verifies BuildParameters.create() correctly maps all Input getters.
3. src/model/orchestrator/services/submodule/submodule-profile-service.test.ts
(5 new tests) - Command construction safety tests for execute(),
documenting how paths, branches, and tokens are passed into git
commands and verifying the expected command strings.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Remove the else branch that actively called GitHooksService.disableHooks()
for every user where gitHooksEnabled was false (the default). This was a
breaking change that silently modified core.hooksPath to point at an empty
directory, disabling any existing git hooks (husky, lefthook, pre-commit, etc.).
When gitHooksEnabled is false (default), the action now does nothing
regarding hooks — exactly matching the behavior on main before the hooks
feature was added. The hooks feature only activates when users explicitly
set gitHooksEnabled: true.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
The monolithic orchestrator-integrity workflow runs 25+ tests sequentially
in a single job, consistently hitting the 60-minute timeout on PR runs.
Split into 4 parallel jobs (k8s, aws-provider, local-docker, rclone) each
on its own runner, cutting wall-clock time from 3+ hours to ~1 hour and
eliminating disk space exhaustion from shared runner contention.
Adopts the parallel architecture from PR #809.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace the npm-only publish-cli.yml with a comprehensive release-cli.yml
that builds standalone binaries via pkg for all platforms (Linux/macOS/Windows,
x64/arm64), uploads them as GitHub Release assets with SHA256 checksums,
and retains npm publish as an optional job.
Add curl-pipe-sh installer (install.sh) and PowerShell installer (install.ps1)
for one-liner installation from GitHub Releases. Both scripts auto-detect
platform/architecture, verify checksums, and guide PATH configuration.
Add `game-ci update` command for self-updating standalone binaries: checks
GitHub releases for newer versions, downloads the correct platform binary,
verifies it, and atomically replaces the running executable.
Distribution strategy: GitHub Releases (primary), npm (optional), with
winget/Homebrew/Chocolatey/Scoop as future providers.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add .github/workflows/publish-cli.yml for publishing the CLI to npm on
release or via manual workflow_dispatch with dry-run support.
Add comprehensive test coverage for the CLI:
- input-mapper.test.ts: 16 tests covering argument mapping, boolean
conversion, yargs internal property filtering, and Cli.options population
- commands.test.ts: 26 tests verifying command exports, builder flags,
default values, and camelCase aliases for all six commands
- cli-integration.test.ts: 8 integration tests spawning the CLI process
to verify help output, version info, and error handling
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Introduces a yargs-based CLI entry point (src/cli.ts) distributed as the
`game-ci` command. The CLI reuses existing unity-builder modules — Input,
BuildParameters, Orchestrator, Docker, MacBuilder — so the same build
engine powers both the GitHub Action and the standalone CLI.
Commands: build, activate, orchestrate, cache (list/restore/clear),
status, version.
Closes#812
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Rewrite the monolith orchestrator-integrity.yml (1110 lines, single job,
3+ hour sequential execution) into 4 parallel jobs that run on separate
runners:
- k8s-tests: k3d cluster + LocalStack, 5 tests
- aws-provider-tests: LocalStack only, 10 tests
- local-docker-tests: Docker + LocalStack for S3 tests, 9 tests
- rclone-tests: rclone + LocalStack, 1 test
Key improvements:
- Wall-clock time drops from ~3h to ~1h (longest single job)
- Disk exhaustion eliminated: each job gets its own fresh 14GB runner
- Cleanup logic deduplicated via sourced shell functions instead of
15 copy-pasted 30-line blocks
- K3d node image cleanup only runs in the k8s job (where it matters)
- Light cleanup (cache + docker prune -f) between tests; heavy cleanup
(prune -af --volumes) only at job boundaries
- workflow_call interface unchanged; integrity-check.yml needs no changes
Ref: #794
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- GitHub Actions: max 4-hour polling with clear timeout error including run URL
- GitLab CI: max 4-hour polling with clear timeout error including pipeline URL
- Remote PowerShell: fix credential split to preserve passwords with colons
(split on first colon only instead of all colons)
- Remote PowerShell: throw clear error when credential format is invalid
- Ansible: validate ansible-playbook binary exists in setupWorkflow
(separate from ansible --version check)
- All timeout errors use core.error() for GitHub Actions annotation visibility
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Validate runner entries when loading from hot-runners.json. Discard
corrupted entries with warnings. Add validateAndRepair() method for
runtime recovery. Validate data before persisting to prevent writing
corrupt state. Handle corrupt persistence files (invalid JSON)
gracefully. Rewrite executeWithTimeout using Promise.race to clean up
transport connections on timeout. Fix pre-existing ESLint violations
in dispatcher and test files.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Check available disk space (cross-platform: wmic/df) before archive
operations to prevent data loss on full disks. Skip archival with
warning if insufficient space (10% safety margin). Clean up partial
archives on tar failure. Proceed with warning when space check fails.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Cap pagination at 100 pages (10,000 runners max), detect GitHub API
rate limiting (403/429) with reset time reporting, add 30-second total
timeout for pagination loop. Log clear diagnostic when no runners found
suggesting possible causes (token permissions, runner registration).
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Check for rclone binary before attempting storage-based uploads.
Validate storage destination URI format (remoteName:path).
Provide clear error message with install link when rclone is missing.
Fail gracefully instead of cryptic ENOENT crash.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Validate secret key names against alphanumeric allowlist before shell interpolation
- Apply validation in both SecretSourceService.fetchSecret() and legacy queryOverride()
- Mask fetched secret values with core.setSecret() to prevent log exposure
- Add 20 new tests for validation and masking
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Prevent builds from hanging indefinitely when CLI provider subprocess
is unresponsive. Default 2h for runTaskInWorkflow, 1h for watchWorkflow.
Graceful SIGTERM with 10s grace before SIGKILL.
- Added RUN_TASK_TIMEOUT_MS (2 hours) and WATCH_WORKFLOW_TIMEOUT_MS (1 hour)
- Added gracefulKill helper: SIGTERM first, SIGKILL after 10s grace period
- runTaskInWorkflow and watchWorkflow now have timeout protection
- Existing execute() method upgraded to use gracefulKill
- core.error() called with clear human-readable timeout message
- Added comprehensive tests: timeout triggers, SIGKILL escalation,
grace period cancellation on voluntary exit, normal completion
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace execSync with promisified exec so Promise.all actually runs
test groups in parallel. Add native timeout support via exec options.
Add 50MB maxBuffer for large Unity output. Fix ESLint violations
(variable naming, padding lines, array push consolidation).
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Implement two-level workspace isolation pattern for enterprise-scale CI:
- Atomic O(1) workspace restore via filesystem move (no tar/download/extract)
- Separate Library caching for independent restore
- .git preservation for delta operations
- Stale workspace cleanup with configurable retention policies
- 5 new action inputs: childWorkspacesEnabled, childWorkspaceName,
childWorkspaceCacheRoot, childWorkspacePreserveGit,
childWorkspaceSeparateLibrary
- 28 unit tests covering all service methods
This enables enterprise CI where workspaces are 50GB+ and traditional
caching via actions/cache is impractical. On NTFS, workspace restore
is O(1) via atomic rename when source and destination are on the same volume.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add storage-pull strategy: rclone-based sync from remote storage with
overlay and clean modes, URI parsing (storage://remote:bucket/path),
transfer parallelism, and automatic rclone availability checking
- Add SyncStateManager: persistent state load/save with configurable
paths, workspace hash calculation via SHA-256 of key project files,
and drift detection for external modification awareness
- Add action.yml inputs: syncStrategy, syncInputRef, syncStorageRemote,
syncRevertAfter, syncStatePath with sensible defaults
- Wire sync into Input (5 getters), BuildParameters (5 fields), index.ts
(local build path), and RemoteClient (orchestrator path) with post-job
overlay revert when syncRevertAfter is true
- Add 42 unit tests covering all strategies, URI parsing, state
management, hash calculation, drift detection, error handling, and
edge cases (missing rclone, invalid URIs, absent state, empty diffs)
- Add root:true to eslintrc to prevent plugin resolution conflicts
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add ArtifactUploadHandler with support for github-artifacts, storage (rclone),
and local copy upload targets, including large file chunking for GitHub Artifacts
- Add 44 unit tests covering OutputTypeRegistry, OutputService, and
ArtifactUploadHandler (config parsing, upload coordination, file collection)
- Add 6 new action.yml inputs for artifact configuration
- Add artifactManifestPath action output
- Wire artifact collection and upload into index.ts post-build flow
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Adds persistent Unity editor instance support to reduce build iteration time
by eliminating cold-start overhead. Includes:
- HotRunnerTypes: interfaces for config, status, job request/result, transport
- HotRunnerRegistry: in-memory runner management with file-based persistence
- HotRunnerHealthMonitor: periodic health checks, idle recycling, job-count recycling
- HotRunnerDispatcher: job routing with wait-for-runner, timeout, and output streaming
- HotRunnerService: high-level API integrating registry, health, and dispatch
- 34 unit tests covering registration, filtering, health, dispatch, timeout, fallback
- action.yml inputs for hot runner configuration (7 new inputs)
- Input/BuildParameters integration for hot runner settings
- index.ts wiring with cold-build fallback when hot runner unavailable
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Adds BuildReliabilityService with the following capabilities:
- checkGitIntegrity(): runs git fsck --no-dangling and parses output for corruption
- cleanStaleLockFiles(): removes stale .lock files older than 10 minutes
- validateSubmoduleBackingStores(): validates .git files point to valid backing stores
- recoverCorruptedRepo(): orchestrates fsck, lock cleanup, re-fetch, retry fsck
- cleanReservedFilenames(): removes Windows reserved filenames (con, prn, aux, nul, com1-9, lpt1-9)
- archiveBuildOutput(): creates tar.gz archive of build output
- enforceRetention(): deletes archives older than retention period
- configureGitEnvironment(): sets GIT_TERMINAL_PROMPT=0, http.postBuffer, core.longpaths
Wired into action.yml as opt-in inputs, with pre-build integrity checks and
post-build archival in the main entry point.
Includes 29 unit tests covering success and failure cases for all methods.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add three optional reliability features for hardening CI pipelines:
- Git corruption detection & recovery (fsck, stale lock cleanup,
submodule backing store validation, auto-recovery)
- Reserved filename cleanup (removes Windows device names that
cause Unity asset importer infinite loops)
- Build output archival with configurable retention policy
All features are opt-in and fail gracefully with warnings only.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add four new providers that delegate builds to external CI platforms:
- remote-powershell: Execute on remote machines via WinRM/SSH
- github-actions: Dispatch workflow_dispatch on target repository
- gitlab-ci: Trigger pipeline via GitLab API
- ansible: Run playbooks against managed inventory
Each follows the CI-as-a-provider pattern: trigger remote job,
pass build parameters, stream logs, report status.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add scheduled workflow that validates community Unity packages compile
and build correctly using unity-builder. Runs weekly on Sunday.
Includes:
- YAML plugin registry (community-plugins.yml) for package listings
- Matrix expansion across plugins and platforms
- Automatic failure reporting via GitHub issues
- Manual trigger with plugin filter and Unity version override
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Built-in support for Unity Git Hooks (com.frostebite.unitygithooks):
- Auto-detect UPM package in Packages/manifest.json
- Run init-unity-lefthook.js before hook installation
- Set CI-friendly env vars (disable background project mode)
New gitHooksRunBeforeBuild input runs specific lefthook groups before
the Unity build, allowing CI to trigger pre-commit or pre-push checks
that normally only fire on git events.
35 unit tests covering detection, init, CI env, group execution, and
failure handling.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
First-class support for elastic-git-storage as a custom LFS transfer
agent. When lfsTransferAgent is set to "elastic-git-storage" (or
"[email protected]" for a specific version), the service
automatically finds or installs the agent from GitHub releases, then
configures it via git config.
Supports version pinning via @version suffix in the agent value,
eliminating the need for a separate version parameter. Platform and
architecture detection handles linux/darwin/windows on amd64/arm64.
37 unit tests covering detection, PATH lookup, installation, version
parsing, and configuration delegation.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Adds three Vault entries: hashicorp-vault (KV v2), hashicorp-vault-kv1
(KV v1), and vault (short alias). Uses VAULT_ADDR for server address and
VAULT_MOUNT env var for configurable mount path (defaults to 'secret').
Refs #776
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace token-in-URL pattern with http.extraHeader for git clone and LFS
operations. The token no longer appears in clone URLs, git remote config,
or process command lines.
Add gitAuthMode input (default: 'header', legacy: 'url') so users can
fall back to the old behavior if needed.
Closes#785
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add comprehensive tests for CLI provider (cleanupWorkflow, garbageCollect,
listWorkflow, watchWorkflow, stderr forwarding, timeout handling), local
cache service (saveLfsCache full path and error handling), git hooks service
(husky install, failure logging, edge cases), and LFS agent service (empty
storagePaths, validate logging). 73 tests across 4 test files.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Adds a fast-fail unit test step at the top of orchestrator-integrity,
right after yarn install and before any infrastructure setup (k3d,
LocalStack). Runs 113 mock-based orchestrator tests in ~5 seconds.
If serialization, path computation, log parsing, or provider loading
is broken, the workflow fails immediately instead of spending 30+
minutes setting up LocalStack and k3d clusters.
Tests included: orchestrator-guid, orchestrator-folders,
task-parameter-serializer, follow-log-stream-service,
runner-availability-service, provider-url-parser, provider-loader,
provider-git-manager, orchestrator-image, orchestrator-hooks,
orchestrator-github-checks.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Adds 64 new mock-based unit tests covering orchestrator services that
previously had zero test coverage:
- TaskParameterSerializer: env var format conversion, round-trip,
uniqBy deduplication, blocked params, default secrets
- FollowLogStreamService: build output message parsing — end of
transmission, build success/failure detection, error accumulation,
Library rebuild detection
- OrchestratorNamespace (guid): GUID generation format, platform
name normalization, nanoid uniqueness
- OrchestratorFolders: path computation for all folder getters,
ToLinuxFolder conversion, repo URL generation, purge flag detection
All tests are pure mock-based and run without any external
infrastructure (no LocalStack, K8s, Docker, or AWS).
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Covers: no token skip, no runners fallback, busy/offline runners,
label filtering (case-insensitive), minAvailable threshold,
fail-open on API error, mixed runner states.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Adds tests for cache hit restore (picks latest tar), LFS cache
restore/save, garbage collection age filtering, and edge cases
like permission errors and empty directories.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Adds retryOnFallback (retry failed builds on alternate provider) and
providerInitTimeout (swap provider if init takes too long). Refactors
run() into run()/runWithProvider() to support retry loop.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Adds built-in load balancing: check GitHub runner availability before
builds start, auto-route to a fallback provider when runners are busy
or offline. Eliminates the need for a separate check-runner job.
New inputs: fallbackProviderStrategy, runnerCheckEnabled,
runnerCheckLabels, runnerCheckMinAvailable.
Outputs providerFallbackUsed and providerFallbackReason for workflow
visibility.
Co-Authored-By: Claude Opus 4.6 <[email protected]>