chore: Cherry-picked changes from upstream#30
Conversation
|
🚀 PR Updated! The PR has been updated with the latest cherry-picked commits. @step-security/maintained-actions-dev Please review and approve the changes. ❌ Build script failed. No files were committed. 📦 Target Release Version: ❗ Missing Files:
🛑 Workflow Files (Cannot be auto-applied by GitHub Actions):
❌ Conflicting Files:
|
f627e98 to
45aefb4
Compare
…ck (Pipelines), Testing Improvements, Rclone storage support, Provider plugin system (#731)
* Enhance LFS file pulling with token fallback mechanism
- Implemented a primary attempt to pull LFS files using GIT_PRIVATE_TOKEN.
- Added a fallback mechanism to use GITHUB_TOKEN if the initial attempt fails.
- Configured git to replace SSH and HTTPS URLs with token-based authentication for the fallback.
- Improved error handling to log specific failure messages for both token attempts.
This change ensures more robust handling of LFS file retrieval in various authentication scenarios.
* Update GitHub Actions permissions in CI pipeline
- Added permissions for packages, pull-requests, statuses, and id-token to enhance workflow capabilities.
- This change improves the CI pipeline's ability to manage pull requests and access necessary resources.
* Enhance LFS file pulling by configuring git for token-based authentication
- Added configuration to use GIT_PRIVATE_TOKEN for git operations, replacing SSH and HTTPS URLs with token-based authentication.
- Improved error handling to ensure GIT_PRIVATE_TOKEN availability before attempting to pull LFS files.
- This change streamlines the process of pulling LFS files in environments requiring token authentication.
* Refactor git configuration for LFS file pulling with token-based authentication
- Enhanced the process of configuring git to use GIT_PRIVATE_TOKEN and GITHUB_TOKEN by clearing existing URL configurations before setting new ones.
- Improved the clarity of the URL replacement commands for better readability and maintainability.
- This change ensures a more robust setup for pulling LFS files in environments requiring token authentication.
* Update GitHub Actions to use GIT_PRIVATE_TOKEN for GITHUB_TOKEN in CI pipeline
- Replaced instances of GITHUB_TOKEN with GIT_PRIVATE_TOKEN in the cloud-runner CI pipeline configuration.
- This change ensures consistent use of token-based authentication across various jobs in the workflow, enhancing security and functionality.
* Update git configuration commands in RemoteClient to ensure robust URL unsetting
- Modified the git configuration commands to append '|| true' to prevent errors if the specified URLs do not exist.
- This change enhances the reliability of the URL clearing process in the RemoteClient class, ensuring smoother execution during token-based authentication setups.
* fix
* Refactor URL configuration in RemoteClient for token-based authentication
- Updated comments for clarity regarding the purpose of URL configuration changes.
- Simplified the git configuration commands by removing redundant lines while maintaining functionality for HTTPS token-based authentication.
- This change enhances the readability and maintainability of the RemoteClient class's git setup process.
* fix
* fix
* refactor: use AWS SDK for workspace locks
* fix: lazily initialize S3 client
* yarn build
* fix
* Update log output handling in FollowLogStreamService to always append log lines for test assertions
* tests: assert BuildSucceeded; skip S3 locally; AWS describeTasks backoff; lint/format fixes
* style(remote-client): satisfy eslint lines-around-comment; tests: log cache key for retained workspace (#379)
* ci(aws): echo CACHE_KEY during setup to ensure e2e sees cache key in logs; tests: retained workspace AWS assertion (#381)
* chore(format): prettier/eslint fix for build-automation-workflow; guard local provider steps
* refactor(build-automation): enhance containerized workflow handling and log management; update builder path logic based on provider strategy
* refactor(container-hook-service): improve AWS hook inclusion logic based on provider strategy and credentials; update binary files
* test(windows): skip grep tests on win32; logs: echo CACHE_KEY and retained markers; hooks: include AWS S3 hooks on aws provider
* ci(jest): add jest.ci.config with forceExit/detectOpenHandles and test:ci script; fix(windows): skip grep-based version regex tests; logs: echo CACHE_KEY/retained markers; hooks: include AWS hooks on aws provider
* ci: add Integrity workflow using yarn test:ci with forceExit/detectOpenHandles
* refactor(container-hook-service): refine AWS hook inclusion logic and update binary files
* ci: use yarn test:ci in integrity-check; remove redundant integrity.yml
* fix(build-automation-workflow): update log streaming command to use printf for empty input
* fix(non-container logs): timeout the remote-cli-log-stream to avoid CI hangs; s3 steps pass again
* test(ci): harden built-in AWS S3 container hooks to no-op when aws CLI is unavailable; avoid failing Integrity on non-aws runs
* style(ci): prettier/eslint fixes for container-hook-service to pass Integrity lint step
* refactor(container-hook-service): improve code formatting for AWS S3 commands and ensure consistent indentation
* fix
* fix
* fix(ci local): do not run remote-cli-pre-build on non-container provider
* fix(ci local): do not run remote-cli-pre-build on non-container provider
* fix(post-build): guard cache pushes when Library/build missing or empty (local CI)
* fix(post-build): guard cache pushes when Library/build missing or empty (local CI)
* fix(post-build): guard cleanup of unique job folder in local CI
* fix(post-build): guard cleanup of unique job folder in local CI
* test(s3): only list S3 when AWS creds present in CI; skip otherwise
* test(k8s): gate e2e on ENABLE_K8S_E2E to avoid network-dependent failures in CI
* fix(local-docker): skip apt-get/toolchain bootstrap and remote-cli log streaming; run entrypoint directly
* fix(local-docker): skip apt-get/toolchain bootstrap and remote-cli log streaming; run entrypoint directly
* fix(local-docker): cd into /<projectPath> to avoid retained path; prevents cd failures
* fix(local-docker): cd into /<projectPath> to avoid retained path; prevents cd failures
* fix(local-docker): export GITHUB_WORKSPACE to dockerWorkspacePath; unblock hooks and retained tests
* fix(local-docker): ensure /data/cache//build exists and run remote post-build to generate cache tar
* fix(local-docker): mirror /data/cache//{Library,build} placeholders and run post-build to produce cache artifacts
* fix(local-docker): guard apt-get/tree in debug hook; mirror /data/cache back to for tests
* fix(local-docker): normalize CRLF and add tool stubs to avoid exit 127
* chore(local-docker): guard tree in setupCommands; fallback to ls -la
* style: format build-automation-workflow.ts to satisfy Prettier
* test(caching, retaining): echo CACHE_KEY value into log stream for AWS/K8s visibility
* test(post-build): log CACHE_KEY from remote-cli-post-build to ensure visibility in BuildResults
* test(post-build): emit 'Activation successful' to satisfy caching assertions on AWS/K8s
* fix(aws): increase backoff and handle throttling in DescribeTasks/GetRecords
* fix(aws): increase backoff and handle throttling in DescribeTasks/GetRecords
* refactor(workflows): remove deprecated cloud-runner CI pipeline and introduce cloud-runner integrity workflow
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* feat: configure aws endpoints and localstack tests
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: run localstack pipeline in integrity check
* style: format aws-task-runner.ts to satisfy Prettier
* style: format aws-task-runner.ts to satisfy Prettier
* style: format aws-task-runner.ts to satisfy Prettier
* style: format aws-task-runner.ts to satisfy Prettier
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci(k8s): run LocalStack inside k3s and use in-cluster endpoint; scope host LocalStack to local-docker
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* Cloud runner develop rclone (#732)
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* Update README.md
* feat: Add dynamic provider loader with improved error handling (#734)
* feat: Add dynamic provider loader with improved error handling
- Create provider-loader.ts with function-based dynamic import functionality
- Update CloudRunner.setupSelectedBuildPlatform to use dynamic loader for unknown providers
- Add comprehensive error handling for missing packages and interface validation
- Include test coverage for successful loading and error scenarios
- Maintain backward compatibility with existing built-in providers
- Add ProviderLoader class wrapper for backward compatibility
- Support both built-in providers (via switch) and external providers (via dynamic import)
* fix: Resolve linting errors in provider loader
- Fix TypeError usage instead of Error for type checking
- Add missing blank lines for proper code formatting
- Fix comment spacing issues
* build: Update built artifacts after linting fixes
- Rebuild dist/ with latest changes
- Include updated provider loader in built bundle
- Ensure all changes are reflected in compiled output
* build: Update built artifacts after linting fixes
- Rebuild dist/ with latest changes
- Include updated provider loader in built bundle
- Ensure all changes are reflected in compiled output
* build: Update built artifacts after linting fixes
- Rebuild dist/ with latest changes
- Include updated provider loader in built bundle
- Ensure all changes are reflected in compiled output
* build: Update built artifacts after linting fixes
- Rebuild dist/ with latest changes
- Include updated provider loader in built bundle
- Ensure all changes are reflected in compiled output
* fix: Fix AWS job dependencies and remove duplicate localstack tests
- Update AWS job to depend on both k8s and localstack jobs
- Remove duplicate localstack tests from k8s job (now only runs k8s tests)
- Remove unused cloud-runner-localstack job from main integrity check
- Fix AWS SDK warnings by using Uint8Array(0) instead of empty string for S3 PutObject
- Rename localstack-and-k8s job to k8s job for clarity
* feat: Implement provider loader dynamic imports with GitHub URL support
- Add URL detection and parsing utilities for GitHub URLs, local paths, and NPM packages
- Implement git operations for cloning and updating repositories with local caching
- Add automatic update checking mechanism for GitHub repositories
- Update provider-loader.ts to support multiple source types with comprehensive error handling
- Add comprehensive test coverage for all new functionality
- Include complete documentation with usage examples
- Support GitHub URLs: https://github.com/user/repo, user/repo@branch
- Support local paths: ./path, /absolute/path
- Support NPM packages: package-name, @scope/package
- Maintain backward compatibility with existing providers
- Add fallback mechanisms and interface validation
* feat: Implement provider loader dynamic imports with GitHub URL support
- Add URL detection and parsing utilities for GitHub URLs, local paths, and NPM packages
- Implement git operations for cloning and updating repositories with local caching
- Add automatic update checking mechanism for GitHub repositories
- Update provider-loader.ts to support multiple source types with comprehensive error handling
- Add comprehensive test coverage for all new functionality
- Include complete documentation with usage examples
- Support GitHub URLs: https://github.com/user/repo, user/repo@branch
- Support local paths: ./path, /absolute/path
- Support NPM packages: package-name, @scope/package
- Maintain backward compatibility with existing providers
- Add fallback mechanisms and interface validation
* feat: Fix provider-loader tests and URL parser consistency
- Fixed provider-loader test failures (constructor validation, module imports)
- Fixed provider-url-parser to return consistent base URLs for GitHub sources
- Updated error handling to use TypeError consistently
- All provider-loader and provider-url-parser tests now pass
- Fixed prettier and eslint formatting issues
* feat: Implement provider loader dynamic imports with GitHub URL support
- Add URL detection and parsing utilities for GitHub URLs, local paths, and NPM packages
- Implement git operations for cloning and updating repositories with local caching
- Add automatic update checking mechanism for GitHub repositories
- Update provider-loader.ts to support multiple source types with comprehensive error handling
- Add comprehensive test coverage for all new functionality
- Include complete documentation with usage examples
- Support GitHub URLs: https://github.com/user/repo, user/repo@branch
- Support local paths: ./path, /absolute/path
- Support NPM packages: package-name, @scope/package
- Maintain backward compatibility with existing providers
- Add fallback mechanisms and interface validation
* feat: Implement provider loader dynamic imports with GitHub URL support
- Add URL detection and parsing utilities for GitHub URLs, local paths, and NPM packages
- Implement git operations for cloning and updating repositories with local caching
- Add automatic update checking mechanism for GitHub repositories
- Update provider-loader.ts to support multiple source types with comprehensive error handling
- Add comprehensive test coverage for all new functionality
- Include complete documentation with usage examples
- Support GitHub URLs: https://github.com/user/repo, user/repo@branch
- Support local paths: ./path, /absolute/path
- Support NPM packages: package-name, @scope/package
- Maintain backward compatibility with existing providers
- Add fallback mechanisms and interface validation
* m
* m
* Delete .cursor/settings.json
* Update src/model/cloud-runner/providers/README.md
* fix
* fix
* fix
* fix
* PR feedback
* PR feedback
* Update .github/workflows/cloud-runner-integrity.yml
* Update .github/workflows/cloud-runner-integrity.yml
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* pr feedback
* PR feedback
* PR feedback
* pr feedback
* PR feedback
* pr feedback
* pr feedback
* pr feedback
* PR feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback - test should fail on evictions
* pr feedback - fix cleanup loop timeout
* pr feedback - handle evictions and wait for disk pressure condition
* pr feedback - remove ephemeral-storage request for tests
* pr feedback - fix taint removal syntax
* pr feedback - fail faster on pending pods and detect scheduling failures
* pr feedback - cleanup images before job creation and use IfNotPresent
* pr feedback - pre-pull Unity image into k3d node
* Improve k3d cleanup in integrity workflow
* Harden k3d cleanup to avoid disk exhaustion
* pr feedback
* pr feedback - improve pod scheduling diagnostics and remove eviction thresholds that prevent scheduling
* pr feedback - increase timeout for image pulls in tests and detect active image pulls to allow more time
* pr feedback - pre-pull Unity image at cluster setup to avoid runtime disk pressure evictions
* pr feedback - ensure pre-pull pod ephemeral storage is fully reclaimed before tests
* Add host disk cleanup before k3d cluster creation to prevent evictions
* Run LocalStack as managed Docker step for better resource control
* Improve LocalStack readiness checks and add retries for S3 bucket creation
* Unify k8s, localstack, and localDocker jobs into single job with separate steps for better disk space management
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* f
* fix
* fix
* fixes
* fixes
* fixes
* fixes
* fix
* fix
* fix: k3d/LocalStack networking - use shared Docker network and container name
* fix: rename LOCALSTACK_HOST to K8S_LOCALSTACK_HOST to avoid awslocal conflict
* fix: skip AWS environment test (requires LocalStack Pro for full CloudFormation)
* fix: remove EFS from AWS stack - use S3 caching for storage instead
* Revert "fix: remove EFS from AWS stack - use S3 caching for storage instead"
This reverts commit fdb7286204e66367a863611237936da2dbd10018.
* fix: enable EFS and all AWS services in LocalStack, re-enable AWS environment test
* fix: add secretsmanager and other services to LocalStack
* fix: add aws-local mode - validates AWS CloudFormation templates, executes via local-docker
* fix: add rclone integration test with LocalStack S3 backend
* chore: remove temp log files and debug artifacts
* fix: address PR review feedback from GabLeRoux
- Update kubectl to v1.34.1 (latest stable)
- Add provider documentation explaining what a provider is
- Fix typo: "versions" -> "tags" in best practices
* integrate PR #686
* integrate PR #686
* lint fix
* fix: use /bin/sh for Alpine-based images (rclone/rclone) in docker provider
* fix: lint issues
* fix: restore GitHub API workflow_id convention and getCheckStatus method
Reverts cosmetic changes that renamed workflow_id to workflowId in GitHub
API calls. The GitHub REST API uses workflow_id, so we keep the eslint
camelcase suppression comments to match the official API convention.
Also restores the getCheckStatus() method that was removed.
* revert: remove unrelated changes to docker.ts, github.ts, image-tag.ts, versioning.test.ts
These files had changes unrelated to the Cloud Runner improvements PR goals.
Reverting to main branch state.
* fix: use /bin/sh for Alpine-based images (rclone/rclone) in docker provider
The rclone/rclone image is Alpine-based and only has /bin/sh, not /bin/bash.
This fixes exit code 127 errors when running rclone commands in containers.
* fix: fetch only specific PR ref instead of all PR refs
The previous implementation fetched ALL PR refs with:
git fetch origin +refs/pull/*:refs/remotes/origin/pull/*
This is extremely slow for repos with many PRs (700+ PRs in unity-builder).
Now fetches only the specific PR ref needed, e.g., for pull/731/merge:
git fetch origin +refs/pull/731/merge:... +refs/pull/731/head:...
This should significantly speed up the Cloud Runner integrity tests.
* chore: remove cleanup.yml workflow
* chore: remove redundant cloud-runner-integrity-localstack.yml
Tests are already covered by cloud-runner-integrity.yml
---------
…ck (Pipelines), Testing Improvements, Rclone storage support, Provider plugin system (#731)
* Enhance LFS file pulling with token fallback mechanism
- Implemented a primary attempt to pull LFS files using GIT_PRIVATE_TOKEN.
- Added a fallback mechanism to use GITHUB_TOKEN if the initial attempt fails.
- Configured git to replace SSH and HTTPS URLs with token-based authentication for the fallback.
- Improved error handling to log specific failure messages for both token attempts.
This change ensures more robust handling of LFS file retrieval in various authentication scenarios.
* Update GitHub Actions permissions in CI pipeline
- Added permissions for packages, pull-requests, statuses, and id-token to enhance workflow capabilities.
- This change improves the CI pipeline's ability to manage pull requests and access necessary resources.
* Enhance LFS file pulling by configuring git for token-based authentication
- Added configuration to use GIT_PRIVATE_TOKEN for git operations, replacing SSH and HTTPS URLs with token-based authentication.
- Improved error handling to ensure GIT_PRIVATE_TOKEN availability before attempting to pull LFS files.
- This change streamlines the process of pulling LFS files in environments requiring token authentication.
* Refactor git configuration for LFS file pulling with token-based authentication
- Enhanced the process of configuring git to use GIT_PRIVATE_TOKEN and GITHUB_TOKEN by clearing existing URL configurations before setting new ones.
- Improved the clarity of the URL replacement commands for better readability and maintainability.
- This change ensures a more robust setup for pulling LFS files in environments requiring token authentication.
* Update GitHub Actions to use GIT_PRIVATE_TOKEN for GITHUB_TOKEN in CI pipeline
- Replaced instances of GITHUB_TOKEN with GIT_PRIVATE_TOKEN in the cloud-runner CI pipeline configuration.
- This change ensures consistent use of token-based authentication across various jobs in the workflow, enhancing security and functionality.
* Update git configuration commands in RemoteClient to ensure robust URL unsetting
- Modified the git configuration commands to append '|| true' to prevent errors if the specified URLs do not exist.
- This change enhances the reliability of the URL clearing process in the RemoteClient class, ensuring smoother execution during token-based authentication setups.
* fix
* Refactor URL configuration in RemoteClient for token-based authentication
- Updated comments for clarity regarding the purpose of URL configuration changes.
- Simplified the git configuration commands by removing redundant lines while maintaining functionality for HTTPS token-based authentication.
- This change enhances the readability and maintainability of the RemoteClient class's git setup process.
* fix
* fix
* refactor: use AWS SDK for workspace locks
* fix: lazily initialize S3 client
* yarn build
* fix
* Update log output handling in FollowLogStreamService to always append log lines for test assertions
* tests: assert BuildSucceeded; skip S3 locally; AWS describeTasks backoff; lint/format fixes
* style(remote-client): satisfy eslint lines-around-comment; tests: log cache key for retained workspace (#379)
* ci(aws): echo CACHE_KEY during setup to ensure e2e sees cache key in logs; tests: retained workspace AWS assertion (#381)
* chore(format): prettier/eslint fix for build-automation-workflow; guard local provider steps
* refactor(build-automation): enhance containerized workflow handling and log management; update builder path logic based on provider strategy
* refactor(container-hook-service): improve AWS hook inclusion logic based on provider strategy and credentials; update binary files
* test(windows): skip grep tests on win32; logs: echo CACHE_KEY and retained markers; hooks: include AWS S3 hooks on aws provider
* ci(jest): add jest.ci.config with forceExit/detectOpenHandles and test:ci script; fix(windows): skip grep-based version regex tests; logs: echo CACHE_KEY/retained markers; hooks: include AWS hooks on aws provider
* ci: add Integrity workflow using yarn test:ci with forceExit/detectOpenHandles
* refactor(container-hook-service): refine AWS hook inclusion logic and update binary files
* ci: use yarn test:ci in integrity-check; remove redundant integrity.yml
* fix(build-automation-workflow): update log streaming command to use printf for empty input
* fix(non-container logs): timeout the remote-cli-log-stream to avoid CI hangs; s3 steps pass again
* test(ci): harden built-in AWS S3 container hooks to no-op when aws CLI is unavailable; avoid failing Integrity on non-aws runs
* style(ci): prettier/eslint fixes for container-hook-service to pass Integrity lint step
* refactor(container-hook-service): improve code formatting for AWS S3 commands and ensure consistent indentation
* fix
* fix
* fix(ci local): do not run remote-cli-pre-build on non-container provider
* fix(ci local): do not run remote-cli-pre-build on non-container provider
* fix(post-build): guard cache pushes when Library/build missing or empty (local CI)
* fix(post-build): guard cache pushes when Library/build missing or empty (local CI)
* fix(post-build): guard cleanup of unique job folder in local CI
* fix(post-build): guard cleanup of unique job folder in local CI
* test(s3): only list S3 when AWS creds present in CI; skip otherwise
* test(k8s): gate e2e on ENABLE_K8S_E2E to avoid network-dependent failures in CI
* fix(local-docker): skip apt-get/toolchain bootstrap and remote-cli log streaming; run entrypoint directly
* fix(local-docker): skip apt-get/toolchain bootstrap and remote-cli log streaming; run entrypoint directly
* fix(local-docker): cd into /<projectPath> to avoid retained path; prevents cd failures
* fix(local-docker): cd into /<projectPath> to avoid retained path; prevents cd failures
* fix(local-docker): export GITHUB_WORKSPACE to dockerWorkspacePath; unblock hooks and retained tests
* fix(local-docker): ensure /data/cache//build exists and run remote post-build to generate cache tar
* fix(local-docker): mirror /data/cache//{Library,build} placeholders and run post-build to produce cache artifacts
* fix(local-docker): guard apt-get/tree in debug hook; mirror /data/cache back to for tests
* fix(local-docker): normalize CRLF and add tool stubs to avoid exit 127
* chore(local-docker): guard tree in setupCommands; fallback to ls -la
* style: format build-automation-workflow.ts to satisfy Prettier
* test(caching, retaining): echo CACHE_KEY value into log stream for AWS/K8s visibility
* test(post-build): log CACHE_KEY from remote-cli-post-build to ensure visibility in BuildResults
* test(post-build): emit 'Activation successful' to satisfy caching assertions on AWS/K8s
* fix(aws): increase backoff and handle throttling in DescribeTasks/GetRecords
* fix(aws): increase backoff and handle throttling in DescribeTasks/GetRecords
* refactor(workflows): remove deprecated cloud-runner CI pipeline and introduce cloud-runner integrity workflow
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* feat: configure aws endpoints and localstack tests
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: run localstack pipeline in integrity check
* style: format aws-task-runner.ts to satisfy Prettier
* style: format aws-task-runner.ts to satisfy Prettier
* style: format aws-task-runner.ts to satisfy Prettier
* style: format aws-task-runner.ts to satisfy Prettier
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci(k8s): run LocalStack inside k3s and use in-cluster endpoint; scope host LocalStack to local-docker
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* Cloud runner develop rclone (#732)
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* Update README.md
* feat: Add dynamic provider loader with improved error handling (#734)
* feat: Add dynamic provider loader with improved error handling
- Create provider-loader.ts with function-based dynamic import functionality
- Update CloudRunner.setupSelectedBuildPlatform to use dynamic loader for unknown providers
- Add comprehensive error handling for missing packages and interface validation
- Include test coverage for successful loading and error scenarios
- Maintain backward compatibility with existing built-in providers
- Add ProviderLoader class wrapper for backward compatibility
- Support both built-in providers (via switch) and external providers (via dynamic import)
* fix: Resolve linting errors in provider loader
- Fix TypeError usage instead of Error for type checking
- Add missing blank lines for proper code formatting
- Fix comment spacing issues
* build: Update built artifacts after linting fixes
- Rebuild dist/ with latest changes
- Include updated provider loader in built bundle
- Ensure all changes are reflected in compiled output
* build: Update built artifacts after linting fixes
- Rebuild dist/ with latest changes
- Include updated provider loader in built bundle
- Ensure all changes are reflected in compiled output
* build: Update built artifacts after linting fixes
- Rebuild dist/ with latest changes
- Include updated provider loader in built bundle
- Ensure all changes are reflected in compiled output
* build: Update built artifacts after linting fixes
- Rebuild dist/ with latest changes
- Include updated provider loader in built bundle
- Ensure all changes are reflected in compiled output
* fix: Fix AWS job dependencies and remove duplicate localstack tests
- Update AWS job to depend on both k8s and localstack jobs
- Remove duplicate localstack tests from k8s job (now only runs k8s tests)
- Remove unused cloud-runner-localstack job from main integrity check
- Fix AWS SDK warnings by using Uint8Array(0) instead of empty string for S3 PutObject
- Rename localstack-and-k8s job to k8s job for clarity
* feat: Implement provider loader dynamic imports with GitHub URL support
- Add URL detection and parsing utilities for GitHub URLs, local paths, and NPM packages
- Implement git operations for cloning and updating repositories with local caching
- Add automatic update checking mechanism for GitHub repositories
- Update provider-loader.ts to support multiple source types with comprehensive error handling
- Add comprehensive test coverage for all new functionality
- Include complete documentation with usage examples
- Support GitHub URLs: https://github.com/user/repo, user/repo@branch
- Support local paths: ./path, /absolute/path
- Support NPM packages: package-name, @scope/package
- Maintain backward compatibility with existing providers
- Add fallback mechanisms and interface validation
* feat: Implement provider loader dynamic imports with GitHub URL support
- Add URL detection and parsing utilities for GitHub URLs, local paths, and NPM packages
- Implement git operations for cloning and updating repositories with local caching
- Add automatic update checking mechanism for GitHub repositories
- Update provider-loader.ts to support multiple source types with comprehensive error handling
- Add comprehensive test coverage for all new functionality
- Include complete documentation with usage examples
- Support GitHub URLs: https://github.com/user/repo, user/repo@branch
- Support local paths: ./path, /absolute/path
- Support NPM packages: package-name, @scope/package
- Maintain backward compatibility with existing providers
- Add fallback mechanisms and interface validation
* feat: Fix provider-loader tests and URL parser consistency
- Fixed provider-loader test failures (constructor validation, module imports)
- Fixed provider-url-parser to return consistent base URLs for GitHub sources
- Updated error handling to use TypeError consistently
- All provider-loader and provider-url-parser tests now pass
- Fixed prettier and eslint formatting issues
* feat: Implement provider loader dynamic imports with GitHub URL support
- Add URL detection and parsing utilities for GitHub URLs, local paths, and NPM packages
- Implement git operations for cloning and updating repositories with local caching
- Add automatic update checking mechanism for GitHub repositories
- Update provider-loader.ts to support multiple source types with comprehensive error handling
- Add comprehensive test coverage for all new functionality
- Include complete documentation with usage examples
- Support GitHub URLs: https://github.com/user/repo, user/repo@branch
- Support local paths: ./path, /absolute/path
- Support NPM packages: package-name, @scope/package
- Maintain backward compatibility with existing providers
- Add fallback mechanisms and interface validation
* feat: Implement provider loader dynamic imports with GitHub URL support
- Add URL detection and parsing utilities for GitHub URLs, local paths, and NPM packages
- Implement git operations for cloning and updating repositories with local caching
- Add automatic update checking mechanism for GitHub repositories
- Update provider-loader.ts to support multiple source types with comprehensive error handling
- Add comprehensive test coverage for all new functionality
- Include complete documentation with usage examples
- Support GitHub URLs: https://github.com/user/repo, user/repo@branch
- Support local paths: ./path, /absolute/path
- Support NPM packages: package-name, @scope/package
- Maintain backward compatibility with existing providers
- Add fallback mechanisms and interface validation
* m
* m
* Delete .cursor/settings.json
* Update src/model/cloud-runner/providers/README.md
* fix
* fix
* fix
* fix
* PR feedback
* PR feedback
* Update .github/workflows/cloud-runner-integrity.yml
* Update .github/workflows/cloud-runner-integrity.yml
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* pr feedback
* PR feedback
* PR feedback
* pr feedback
* PR feedback
* pr feedback
* pr feedback
* pr feedback
* PR feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback - test should fail on evictions
* pr feedback - fix cleanup loop timeout
* pr feedback - handle evictions and wait for disk pressure condition
* pr feedback - remove ephemeral-storage request for tests
* pr feedback - fix taint removal syntax
* pr feedback - fail faster on pending pods and detect scheduling failures
* pr feedback - cleanup images before job creation and use IfNotPresent
* pr feedback - pre-pull Unity image into k3d node
* Improve k3d cleanup in integrity workflow
* Harden k3d cleanup to avoid disk exhaustion
* pr feedback
* pr feedback - improve pod scheduling diagnostics and remove eviction thresholds that prevent scheduling
* pr feedback - increase timeout for image pulls in tests and detect active image pulls to allow more time
* pr feedback - pre-pull Unity image at cluster setup to avoid runtime disk pressure evictions
* pr feedback - ensure pre-pull pod ephemeral storage is fully reclaimed before tests
* Add host disk cleanup before k3d cluster creation to prevent evictions
* Run LocalStack as managed Docker step for better resource control
* Improve LocalStack readiness checks and add retries for S3 bucket creation
* Unify k8s, localstack, and localDocker jobs into single job with separate steps for better disk space management
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* f
* fix
* fix
* fixes
* fixes
* fixes
* fixes
* fix
* fix
* fix: k3d/LocalStack networking - use shared Docker network and container name
* fix: rename LOCALSTACK_HOST to K8S_LOCALSTACK_HOST to avoid awslocal conflict
* fix: skip AWS environment test (requires LocalStack Pro for full CloudFormation)
* fix: remove EFS from AWS stack - use S3 caching for storage instead
* Revert "fix: remove EFS from AWS stack - use S3 caching for storage instead"
This reverts commit fdb7286204e66367a863611237936da2dbd10018.
* fix: enable EFS and all AWS services in LocalStack, re-enable AWS environment test
* fix: add secretsmanager and other services to LocalStack
* fix: add aws-local mode - validates AWS CloudFormation templates, executes via local-docker
* fix: add rclone integration test with LocalStack S3 backend
* chore: remove temp log files and debug artifacts
* fix: address PR review feedback from GabLeRoux
- Update kubectl to v1.34.1 (latest stable)
- Add provider documentation explaining what a provider is
- Fix typo: "versions" -> "tags" in best practices
* integrate PR #686
* integrate PR #686
* lint fix
* fix: use /bin/sh for Alpine-based images (rclone/rclone) in docker provider
* fix: lint issues
* fix: restore GitHub API workflow_id convention and getCheckStatus method
Reverts cosmetic changes that renamed workflow_id to workflowId in GitHub
API calls. The GitHub REST API uses workflow_id, so we keep the eslint
camelcase suppression comments to match the official API convention.
Also restores the getCheckStatus() method that was removed.
* revert: remove unrelated changes to docker.ts, github.ts, image-tag.ts, versioning.test.ts
These files had changes unrelated to the Cloud Runner improvements PR goals.
Reverting to main branch state.
* fix: use /bin/sh for Alpine-based images (rclone/rclone) in docker provider
The rclone/rclone image is Alpine-based and only has /bin/sh, not /bin/bash.
This fixes exit code 127 errors when running rclone commands in containers.
* fix: fetch only specific PR ref instead of all PR refs
The previous implementation fetched ALL PR refs with:
git fetch origin +refs/pull/*:refs/remotes/origin/pull/*
This is extremely slow for repos with many PRs (700+ PRs in unity-builder).
Now fetches only the specific PR ref needed, e.g., for pull/731/merge:
git fetch origin +refs/pull/731/merge:... +refs/pull/731/head:...
This should significantly speed up the Cloud Runner integrity tests.
* chore: remove cleanup.yml workflow
* chore: remove redundant cloud-runner-integrity-localstack.yml
Tests are already covered by cloud-runner-integrity.yml
---------
…ck (Pipelines), Testing Improvements, Rclone storage support, Provider plugin system (#731)
* Enhance LFS file pulling with token fallback mechanism
- Implemented a primary attempt to pull LFS files using GIT_PRIVATE_TOKEN.
- Added a fallback mechanism to use GITHUB_TOKEN if the initial attempt fails.
- Configured git to replace SSH and HTTPS URLs with token-based authentication for the fallback.
- Improved error handling to log specific failure messages for both token attempts.
This change ensures more robust handling of LFS file retrieval in various authentication scenarios.
* Update GitHub Actions permissions in CI pipeline
- Added permissions for packages, pull-requests, statuses, and id-token to enhance workflow capabilities.
- This change improves the CI pipeline's ability to manage pull requests and access necessary resources.
* Enhance LFS file pulling by configuring git for token-based authentication
- Added configuration to use GIT_PRIVATE_TOKEN for git operations, replacing SSH and HTTPS URLs with token-based authentication.
- Improved error handling to ensure GIT_PRIVATE_TOKEN availability before attempting to pull LFS files.
- This change streamlines the process of pulling LFS files in environments requiring token authentication.
* Refactor git configuration for LFS file pulling with token-based authentication
- Enhanced the process of configuring git to use GIT_PRIVATE_TOKEN and GITHUB_TOKEN by clearing existing URL configurations before setting new ones.
- Improved the clarity of the URL replacement commands for better readability and maintainability.
- This change ensures a more robust setup for pulling LFS files in environments requiring token authentication.
* Update GitHub Actions to use GIT_PRIVATE_TOKEN for GITHUB_TOKEN in CI pipeline
- Replaced instances of GITHUB_TOKEN with GIT_PRIVATE_TOKEN in the cloud-runner CI pipeline configuration.
- This change ensures consistent use of token-based authentication across various jobs in the workflow, enhancing security and functionality.
* Update git configuration commands in RemoteClient to ensure robust URL unsetting
- Modified the git configuration commands to append '|| true' to prevent errors if the specified URLs do not exist.
- This change enhances the reliability of the URL clearing process in the RemoteClient class, ensuring smoother execution during token-based authentication setups.
* fix
* Refactor URL configuration in RemoteClient for token-based authentication
- Updated comments for clarity regarding the purpose of URL configuration changes.
- Simplified the git configuration commands by removing redundant lines while maintaining functionality for HTTPS token-based authentication.
- This change enhances the readability and maintainability of the RemoteClient class's git setup process.
* fix
* fix
* refactor: use AWS SDK for workspace locks
* fix: lazily initialize S3 client
* yarn build
* fix
* Update log output handling in FollowLogStreamService to always append log lines for test assertions
* tests: assert BuildSucceeded; skip S3 locally; AWS describeTasks backoff; lint/format fixes
* style(remote-client): satisfy eslint lines-around-comment; tests: log cache key for retained workspace (#379)
* ci(aws): echo CACHE_KEY during setup to ensure e2e sees cache key in logs; tests: retained workspace AWS assertion (#381)
* chore(format): prettier/eslint fix for build-automation-workflow; guard local provider steps
* refactor(build-automation): enhance containerized workflow handling and log management; update builder path logic based on provider strategy
* refactor(container-hook-service): improve AWS hook inclusion logic based on provider strategy and credentials; update binary files
* test(windows): skip grep tests on win32; logs: echo CACHE_KEY and retained markers; hooks: include AWS S3 hooks on aws provider
* ci(jest): add jest.ci.config with forceExit/detectOpenHandles and test:ci script; fix(windows): skip grep-based version regex tests; logs: echo CACHE_KEY/retained markers; hooks: include AWS hooks on aws provider
* ci: add Integrity workflow using yarn test:ci with forceExit/detectOpenHandles
* refactor(container-hook-service): refine AWS hook inclusion logic and update binary files
* ci: use yarn test:ci in integrity-check; remove redundant integrity.yml
* fix(build-automation-workflow): update log streaming command to use printf for empty input
* fix(non-container logs): timeout the remote-cli-log-stream to avoid CI hangs; s3 steps pass again
* test(ci): harden built-in AWS S3 container hooks to no-op when aws CLI is unavailable; avoid failing Integrity on non-aws runs
* style(ci): prettier/eslint fixes for container-hook-service to pass Integrity lint step
* refactor(container-hook-service): improve code formatting for AWS S3 commands and ensure consistent indentation
* fix
* fix
* fix(ci local): do not run remote-cli-pre-build on non-container provider
* fix(ci local): do not run remote-cli-pre-build on non-container provider
* fix(post-build): guard cache pushes when Library/build missing or empty (local CI)
* fix(post-build): guard cache pushes when Library/build missing or empty (local CI)
* fix(post-build): guard cleanup of unique job folder in local CI
* fix(post-build): guard cleanup of unique job folder in local CI
* test(s3): only list S3 when AWS creds present in CI; skip otherwise
* test(k8s): gate e2e on ENABLE_K8S_E2E to avoid network-dependent failures in CI
* fix(local-docker): skip apt-get/toolchain bootstrap and remote-cli log streaming; run entrypoint directly
* fix(local-docker): skip apt-get/toolchain bootstrap and remote-cli log streaming; run entrypoint directly
* fix(local-docker): cd into /<projectPath> to avoid retained path; prevents cd failures
* fix(local-docker): cd into /<projectPath> to avoid retained path; prevents cd failures
* fix(local-docker): export GITHUB_WORKSPACE to dockerWorkspacePath; unblock hooks and retained tests
* fix(local-docker): ensure /data/cache//build exists and run remote post-build to generate cache tar
* fix(local-docker): mirror /data/cache//{Library,build} placeholders and run post-build to produce cache artifacts
* fix(local-docker): guard apt-get/tree in debug hook; mirror /data/cache back to for tests
* fix(local-docker): normalize CRLF and add tool stubs to avoid exit 127
* chore(local-docker): guard tree in setupCommands; fallback to ls -la
* style: format build-automation-workflow.ts to satisfy Prettier
* test(caching, retaining): echo CACHE_KEY value into log stream for AWS/K8s visibility
* test(post-build): log CACHE_KEY from remote-cli-post-build to ensure visibility in BuildResults
* test(post-build): emit 'Activation successful' to satisfy caching assertions on AWS/K8s
* fix(aws): increase backoff and handle throttling in DescribeTasks/GetRecords
* fix(aws): increase backoff and handle throttling in DescribeTasks/GetRecords
* refactor(workflows): remove deprecated cloud-runner CI pipeline and introduce cloud-runner integrity workflow
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* feat: configure aws endpoints and localstack tests
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: run localstack pipeline in integrity check
* style: format aws-task-runner.ts to satisfy Prettier
* style: format aws-task-runner.ts to satisfy Prettier
* style: format aws-task-runner.ts to satisfy Prettier
* style: format aws-task-runner.ts to satisfy Prettier
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci: add reusable cloud-runner-integrity workflow; wire into Integrity; disable legacy pipeline triggers
* ci(k8s): run LocalStack inside k3s and use in-cluster endpoint; scope host LocalStack to local-docker
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* Cloud runner develop rclone (#732)
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* ci(k8s): remove in-cluster LocalStack; use host LocalStack via localhost:4566 for all; rely on k3d host mapping
* Update README.md
* feat: Add dynamic provider loader with improved error handling (#734)
* feat: Add dynamic provider loader with improved error handling
- Create provider-loader.ts with function-based dynamic import functionality
- Update CloudRunner.setupSelectedBuildPlatform to use dynamic loader for unknown providers
- Add comprehensive error handling for missing packages and interface validation
- Include test coverage for successful loading and error scenarios
- Maintain backward compatibility with existing built-in providers
- Add ProviderLoader class wrapper for backward compatibility
- Support both built-in providers (via switch) and external providers (via dynamic import)
* fix: Resolve linting errors in provider loader
- Fix TypeError usage instead of Error for type checking
- Add missing blank lines for proper code formatting
- Fix comment spacing issues
* build: Update built artifacts after linting fixes
- Rebuild dist/ with latest changes
- Include updated provider loader in built bundle
- Ensure all changes are reflected in compiled output
* build: Update built artifacts after linting fixes
- Rebuild dist/ with latest changes
- Include updated provider loader in built bundle
- Ensure all changes are reflected in compiled output
* build: Update built artifacts after linting fixes
- Rebuild dist/ with latest changes
- Include updated provider loader in built bundle
- Ensure all changes are reflected in compiled output
* build: Update built artifacts after linting fixes
- Rebuild dist/ with latest changes
- Include updated provider loader in built bundle
- Ensure all changes are reflected in compiled output
* fix: Fix AWS job dependencies and remove duplicate localstack tests
- Update AWS job to depend on both k8s and localstack jobs
- Remove duplicate localstack tests from k8s job (now only runs k8s tests)
- Remove unused cloud-runner-localstack job from main integrity check
- Fix AWS SDK warnings by using Uint8Array(0) instead of empty string for S3 PutObject
- Rename localstack-and-k8s job to k8s job for clarity
* feat: Implement provider loader dynamic imports with GitHub URL support
- Add URL detection and parsing utilities for GitHub URLs, local paths, and NPM packages
- Implement git operations for cloning and updating repositories with local caching
- Add automatic update checking mechanism for GitHub repositories
- Update provider-loader.ts to support multiple source types with comprehensive error handling
- Add comprehensive test coverage for all new functionality
- Include complete documentation with usage examples
- Support GitHub URLs: https://github.com/user/repo, user/repo@branch
- Support local paths: ./path, /absolute/path
- Support NPM packages: package-name, @scope/package
- Maintain backward compatibility with existing providers
- Add fallback mechanisms and interface validation
* feat: Implement provider loader dynamic imports with GitHub URL support
- Add URL detection and parsing utilities for GitHub URLs, local paths, and NPM packages
- Implement git operations for cloning and updating repositories with local caching
- Add automatic update checking mechanism for GitHub repositories
- Update provider-loader.ts to support multiple source types with comprehensive error handling
- Add comprehensive test coverage for all new functionality
- Include complete documentation with usage examples
- Support GitHub URLs: https://github.com/user/repo, user/repo@branch
- Support local paths: ./path, /absolute/path
- Support NPM packages: package-name, @scope/package
- Maintain backward compatibility with existing providers
- Add fallback mechanisms and interface validation
* feat: Fix provider-loader tests and URL parser consistency
- Fixed provider-loader test failures (constructor validation, module imports)
- Fixed provider-url-parser to return consistent base URLs for GitHub sources
- Updated error handling to use TypeError consistently
- All provider-loader and provider-url-parser tests now pass
- Fixed prettier and eslint formatting issues
* feat: Implement provider loader dynamic imports with GitHub URL support
- Add URL detection and parsing utilities for GitHub URLs, local paths, and NPM packages
- Implement git operations for cloning and updating repositories with local caching
- Add automatic update checking mechanism for GitHub repositories
- Update provider-loader.ts to support multiple source types with comprehensive error handling
- Add comprehensive test coverage for all new functionality
- Include complete documentation with usage examples
- Support GitHub URLs: https://github.com/user/repo, user/repo@branch
- Support local paths: ./path, /absolute/path
- Support NPM packages: package-name, @scope/package
- Maintain backward compatibility with existing providers
- Add fallback mechanisms and interface validation
* feat: Implement provider loader dynamic imports with GitHub URL support
- Add URL detection and parsing utilities for GitHub URLs, local paths, and NPM packages
- Implement git operations for cloning and updating repositories with local caching
- Add automatic update checking mechanism for GitHub repositories
- Update provider-loader.ts to support multiple source types with comprehensive error handling
- Add comprehensive test coverage for all new functionality
- Include complete documentation with usage examples
- Support GitHub URLs: https://github.com/user/repo, user/repo@branch
- Support local paths: ./path, /absolute/path
- Support NPM packages: package-name, @scope/package
- Maintain backward compatibility with existing providers
- Add fallback mechanisms and interface validation
* m
* m
* Delete .cursor/settings.json
* Update src/model/cloud-runner/providers/README.md
* fix
* fix
* fix
* fix
* PR feedback
* PR feedback
* Update .github/workflows/cloud-runner-integrity.yml
* Update .github/workflows/cloud-runner-integrity.yml
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* PR feedback
* pr feedback
* PR feedback
* PR feedback
* pr feedback
* PR feedback
* pr feedback
* pr feedback
* pr feedback
* PR feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback - test should fail on evictions
* pr feedback - fix cleanup loop timeout
* pr feedback - handle evictions and wait for disk pressure condition
* pr feedback - remove ephemeral-storage request for tests
* pr feedback - fix taint removal syntax
* pr feedback - fail faster on pending pods and detect scheduling failures
* pr feedback - cleanup images before job creation and use IfNotPresent
* pr feedback - pre-pull Unity image into k3d node
* Improve k3d cleanup in integrity workflow
* Harden k3d cleanup to avoid disk exhaustion
* pr feedback
* pr feedback - improve pod scheduling diagnostics and remove eviction thresholds that prevent scheduling
* pr feedback - increase timeout for image pulls in tests and detect active image pulls to allow more time
* pr feedback - pre-pull Unity image at cluster setup to avoid runtime disk pressure evictions
* pr feedback - ensure pre-pull pod ephemeral storage is fully reclaimed before tests
* Add host disk cleanup before k3d cluster creation to prevent evictions
* Run LocalStack as managed Docker step for better resource control
* Improve LocalStack readiness checks and add retries for S3 bucket creation
* Unify k8s, localstack, and localDocker jobs into single job with separate steps for better disk space management
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* pr feedback
* f
* fix
* fix
* fixes
* fixes
* fixes
* fixes
* fix
* fix
* fix: k3d/LocalStack networking - use shared Docker network and container name
* fix: rename LOCALSTACK_HOST to K8S_LOCALSTACK_HOST to avoid awslocal conflict
* fix: skip AWS environment test (requires LocalStack Pro for full CloudFormation)
* fix: remove EFS from AWS stack - use S3 caching for storage instead
* Revert "fix: remove EFS from AWS stack - use S3 caching for storage instead"
This reverts commit fdb7286204e66367a863611237936da2dbd10018.
* fix: enable EFS and all AWS services in LocalStack, re-enable AWS environment test
* fix: add secretsmanager and other services to LocalStack
* fix: add aws-local mode - validates AWS CloudFormation templates, executes via local-docker
* fix: add rclone integration test with LocalStack S3 backend
* chore: remove temp log files and debug artifacts
* fix: address PR review feedback from GabLeRoux
- Update kubectl to v1.34.1 (latest stable)
- Add provider documentation explaining what a provider is
- Fix typo: "versions" -> "tags" in best practices
* integrate PR #686
* integrate PR #686
* lint fix
* fix: use /bin/sh for Alpine-based images (rclone/rclone) in docker provider
* fix: lint issues
* fix: restore GitHub API workflow_id convention and getCheckStatus method
Reverts cosmetic changes that renamed workflow_id to workflowId in GitHub
API calls. The GitHub REST API uses workflow_id, so we keep the eslint
camelcase suppression comments to match the official API convention.
Also restores the getCheckStatus() method that was removed.
* revert: remove unrelated changes to docker.ts, github.ts, image-tag.ts, versioning.test.ts
These files had changes unrelated to the Cloud Runner improvements PR goals.
Reverting to main branch state.
* fix: use /bin/sh for Alpine-based images (rclone/rclone) in docker provider
The rclone/rclone image is Alpine-based and only has /bin/sh, not /bin/bash.
This fixes exit code 127 errors when running rclone commands in containers.
* fix: fetch only specific PR ref instead of all PR refs
The previous implementation fetched ALL PR refs with:
git fetch origin +refs/pull/*:refs/remotes/origin/pull/*
This is extremely slow for repos with many PRs (700+ PRs in unity-builder).
Now fetches only the specific PR ref needed, e.g., for pull/731/merge:
git fetch origin +refs/pull/731/merge:... +refs/pull/731/head:...
This should significantly speed up the Cloud Runner integrity tests.
* chore: remove cleanup.yml workflow
* chore: remove redundant cloud-runner-integrity-localstack.yml
Tests are already covered by cloud-runner-integrity.yml
---------
* Rename "Cloud Runner" to "Orchestrator" across entire codebase Breaking change: All CloudRunner classes, options, environment variables, and action.yml inputs have been renamed to Orchestrator equivalents. - Renamed src/model/cloud-runner/ directory to src/model/orchestrator/ - Renamed all cloud-runner-* files to orchestrator-* - Renamed all CloudRunner* classes to Orchestrator* (15+ classes) - Renamed all cloudRunner* properties to orchestrator* equivalents - Renamed CLOUD_RUNNER_* env vars to ORCHESTRATOR_* - Updated action.yml [CloudRunner] markers to [Orchestrator] - Updated workflow files and package.json test scripts - Updated all runtime strings (cache paths, log messages, branch refs) - Rebuilt dist/index.js No backward compatibility layer is provided. * Remove tracked log/temp files and add to .gitignore Remove $LOG_FILE and temp/job-log.txt debug artifacts that should not be in the repository. ---------
* Rename "Cloud Runner" to "Orchestrator" across entire codebase Breaking change: All CloudRunner classes, options, environment variables, and action.yml inputs have been renamed to Orchestrator equivalents. - Renamed src/model/cloud-runner/ directory to src/model/orchestrator/ - Renamed all cloud-runner-* files to orchestrator-* - Renamed all CloudRunner* classes to Orchestrator* (15+ classes) - Renamed all cloudRunner* properties to orchestrator* equivalents - Renamed CLOUD_RUNNER_* env vars to ORCHESTRATOR_* - Updated action.yml [CloudRunner] markers to [Orchestrator] - Updated workflow files and package.json test scripts - Updated all runtime strings (cache paths, log messages, branch refs) - Rebuilt dist/index.js No backward compatibility layer is provided. * Remove tracked log/temp files and add to .gitignore Remove $LOG_FILE and temp/job-log.txt debug artifacts that should not be in the repository. ---------
* Rename "Cloud Runner" to "Orchestrator" across entire codebase Breaking change: All CloudRunner classes, options, environment variables, and action.yml inputs have been renamed to Orchestrator equivalents. - Renamed src/model/cloud-runner/ directory to src/model/orchestrator/ - Renamed all cloud-runner-* files to orchestrator-* - Renamed all CloudRunner* classes to Orchestrator* (15+ classes) - Renamed all cloudRunner* properties to orchestrator* equivalents - Renamed CLOUD_RUNNER_* env vars to ORCHESTRATOR_* - Updated action.yml [CloudRunner] markers to [Orchestrator] - Updated workflow files and package.json test scripts - Updated all runtime strings (cache paths, log messages, branch refs) - Rebuilt dist/index.js No backward compatibility layer is provided. * Remove tracked log/temp files and add to .gitignore Remove $LOG_FILE and temp/job-log.txt debug artifacts that should not be in the repository. ---------
* Rename "Cloud Runner" to "Orchestrator" across entire codebase Breaking change: All CloudRunner classes, options, environment variables, and action.yml inputs have been renamed to Orchestrator equivalents. - Renamed src/model/cloud-runner/ directory to src/model/orchestrator/ - Renamed all cloud-runner-* files to orchestrator-* - Renamed all CloudRunner* classes to Orchestrator* (15+ classes) - Renamed all cloudRunner* properties to orchestrator* equivalents - Renamed CLOUD_RUNNER_* env vars to ORCHESTRATOR_* - Updated action.yml [CloudRunner] markers to [Orchestrator] - Updated workflow files and package.json test scripts - Updated all runtime strings (cache paths, log messages, branch refs) - Rebuilt dist/index.js No backward compatibility layer is provided. * Remove tracked log/temp files and add to .gitignore Remove $LOG_FILE and temp/job-log.txt debug artifacts that should not be in the repository. ---------
* Rename "Cloud Runner" to "Orchestrator" across entire codebase Breaking change: All CloudRunner classes, options, environment variables, and action.yml inputs have been renamed to Orchestrator equivalents. - Renamed src/model/cloud-runner/ directory to src/model/orchestrator/ - Renamed all cloud-runner-* files to orchestrator-* - Renamed all CloudRunner* classes to Orchestrator* (15+ classes) - Renamed all cloudRunner* properties to orchestrator* equivalents - Renamed CLOUD_RUNNER_* env vars to ORCHESTRATOR_* - Updated action.yml [CloudRunner] markers to [Orchestrator] - Updated workflow files and package.json test scripts - Updated all runtime strings (cache paths, log messages, branch refs) - Rebuilt dist/index.js No backward compatibility layer is provided. * Remove tracked log/temp files and add to .gitignore Remove $LOG_FILE and temp/job-log.txt debug artifacts that should not be in the repository. ---------
* Rename "Cloud Runner" to "Orchestrator" across entire codebase Breaking change: All CloudRunner classes, options, environment variables, and action.yml inputs have been renamed to Orchestrator equivalents. - Renamed src/model/cloud-runner/ directory to src/model/orchestrator/ - Renamed all cloud-runner-* files to orchestrator-* - Renamed all CloudRunner* classes to Orchestrator* (15+ classes) - Renamed all cloudRunner* properties to orchestrator* equivalents - Renamed CLOUD_RUNNER_* env vars to ORCHESTRATOR_* - Updated action.yml [CloudRunner] markers to [Orchestrator] - Updated workflow files and package.json test scripts - Updated all runtime strings (cache paths, log messages, branch refs) - Rebuilt dist/index.js No backward compatibility layer is provided. * Remove tracked log/temp files and add to .gitignore Remove $LOG_FILE and temp/job-log.txt debug artifacts that should not be in the repository. ---------
* Rename "Cloud Runner" to "Orchestrator" across entire codebase Breaking change: All CloudRunner classes, options, environment variables, and action.yml inputs have been renamed to Orchestrator equivalents. - Renamed src/model/cloud-runner/ directory to src/model/orchestrator/ - Renamed all cloud-runner-* files to orchestrator-* - Renamed all CloudRunner* classes to Orchestrator* (15+ classes) - Renamed all cloudRunner* properties to orchestrator* equivalents - Renamed CLOUD_RUNNER_* env vars to ORCHESTRATOR_* - Updated action.yml [CloudRunner] markers to [Orchestrator] - Updated workflow files and package.json test scripts - Updated all runtime strings (cache paths, log messages, branch refs) - Rebuilt dist/index.js No backward compatibility layer is provided. * Remove tracked log/temp files and add to .gitignore Remove $LOG_FILE and temp/job-log.txt debug artifacts that should not be in the repository. ---------
* Rename "Cloud Runner" to "Orchestrator" across entire codebase Breaking change: All CloudRunner classes, options, environment variables, and action.yml inputs have been renamed to Orchestrator equivalents. - Renamed src/model/cloud-runner/ directory to src/model/orchestrator/ - Renamed all cloud-runner-* files to orchestrator-* - Renamed all CloudRunner* classes to Orchestrator* (15+ classes) - Renamed all cloudRunner* properties to orchestrator* equivalents - Renamed CLOUD_RUNNER_* env vars to ORCHESTRATOR_* - Updated action.yml [CloudRunner] markers to [Orchestrator] - Updated workflow files and package.json test scripts - Updated all runtime strings (cache paths, log messages, branch refs) - Rebuilt dist/index.js No backward compatibility layer is provided. * Remove tracked log/temp files and add to .gitignore Remove $LOG_FILE and temp/job-log.txt debug artifacts that should not be in the repository. ---------
* Rename "Cloud Runner" to "Orchestrator" across entire codebase Breaking change: All CloudRunner classes, options, environment variables, and action.yml inputs have been renamed to Orchestrator equivalents. - Renamed src/model/cloud-runner/ directory to src/model/orchestrator/ - Renamed all cloud-runner-* files to orchestrator-* - Renamed all CloudRunner* classes to Orchestrator* (15+ classes) - Renamed all cloudRunner* properties to orchestrator* equivalents - Renamed CLOUD_RUNNER_* env vars to ORCHESTRATOR_* - Updated action.yml [CloudRunner] markers to [Orchestrator] - Updated workflow files and package.json test scripts - Updated all runtime strings (cache paths, log messages, branch refs) - Rebuilt dist/index.js No backward compatibility layer is provided. * Remove tracked log/temp files and add to .gitignore Remove $LOG_FILE and temp/job-log.txt debug artifacts that should not be in the repository. ---------
* Rename "Cloud Runner" to "Orchestrator" across entire codebase Breaking change: All CloudRunner classes, options, environment variables, and action.yml inputs have been renamed to Orchestrator equivalents. - Renamed src/model/cloud-runner/ directory to src/model/orchestrator/ - Renamed all cloud-runner-* files to orchestrator-* - Renamed all CloudRunner* classes to Orchestrator* (15+ classes) - Renamed all cloudRunner* properties to orchestrator* equivalents - Renamed CLOUD_RUNNER_* env vars to ORCHESTRATOR_* - Updated action.yml [CloudRunner] markers to [Orchestrator] - Updated workflow files and package.json test scripts - Updated all runtime strings (cache paths, log messages, branch refs) - Rebuilt dist/index.js No backward compatibility layer is provided. * Remove tracked log/temp files and add to .gitignore Remove $LOG_FILE and temp/job-log.txt debug artifacts that should not be in the repository. ---------
* Rename "Cloud Runner" to "Orchestrator" across entire codebase Breaking change: All CloudRunner classes, options, environment variables, and action.yml inputs have been renamed to Orchestrator equivalents. - Renamed src/model/cloud-runner/ directory to src/model/orchestrator/ - Renamed all cloud-runner-* files to orchestrator-* - Renamed all CloudRunner* classes to Orchestrator* (15+ classes) - Renamed all cloudRunner* properties to orchestrator* equivalents - Renamed CLOUD_RUNNER_* env vars to ORCHESTRATOR_* - Updated action.yml [CloudRunner] markers to [Orchestrator] - Updated workflow files and package.json test scripts - Updated all runtime strings (cache paths, log messages, branch refs) - Rebuilt dist/index.js No backward compatibility layer is provided. * Remove tracked log/temp files and add to .gitignore Remove $LOG_FILE and temp/job-log.txt debug artifacts that should not be in the repository. ---------
…rides (#821) * fix: pass Unity license secrets to AWS ECS container via RunTask overrides The AWS provider was not passing UNITY_EMAIL, UNITY_PASSWORD, and UNITY_SERIAL to the ECS container as environment variables. These secrets were only sent to CloudFormation Secrets Manager, but the template generation produced duplicate YAML Secrets keys (one per secret), causing only the last secret to survive. The activate.sh script requires all three to be present simultaneously. This fix merges secrets into the ECS RunTask containerOverrides environment array, matching how the docker and k8s providers already handle secrets. The CloudFormation Secrets Manager path is preserved as a secondary mechanism. Fixes license activation failure when using providerStrategy: aws. * Pin LocalStack to 4.4.0 (pre-auth-token requirement) As of 2026-03-23, localstack/localstack:latest requires an auth token even for community features. Pin to 4.4.0 (last community release before the single-image migration) to restore CI. See: https://blog.localstack.cloud/localstack-single-image-next-steps/ ---------
…rides (#821) * fix: pass Unity license secrets to AWS ECS container via RunTask overrides The AWS provider was not passing UNITY_EMAIL, UNITY_PASSWORD, and UNITY_SERIAL to the ECS container as environment variables. These secrets were only sent to CloudFormation Secrets Manager, but the template generation produced duplicate YAML Secrets keys (one per secret), causing only the last secret to survive. The activate.sh script requires all three to be present simultaneously. This fix merges secrets into the ECS RunTask containerOverrides environment array, matching how the docker and k8s providers already handle secrets. The CloudFormation Secrets Manager path is preserved as a secondary mechanism. Fixes license activation failure when using providerStrategy: aws. * Pin LocalStack to 4.4.0 (pre-auth-token requirement) As of 2026-03-23, localstack/localstack:latest requires an auth token even for community features. Pin to 4.4.0 (last community release before the single-image migration) to restore CI. See: https://blog.localstack.cloud/localstack-single-image-next-steps/ ---------
… (#819)
* feat(orchestrator): enterprise feature support — CLI provider, submodule profiles, caching, LFS, hooks
Add generic enterprise-grade features to the orchestrator, enabling Unity projects with
complex CI/CD pipelines to adopt game-ci/unity-builder with built-in support for:
- CLI provider protocol: JSON-over-stdin/stdout bridge enabling providers in any language
(Go, Python, Rust, shell) via the `providerExecutable` input
- Submodule profiles: YAML-based selective submodule initialization with glob patterns
and variant overlays (`submoduleProfilePath`, `submoduleVariantPath`)
- Local build caching: Filesystem-based Library and LFS caching for local builds without
external cache actions (`localCacheEnabled`, `localCacheRoot`)
- Custom LFS transfer agents: Register external transfer agents like elastic-git-storage
(`lfsTransferAgent`, `lfsTransferAgentArgs`, `lfsStoragePaths`)
- Git hooks support: Detect and install lefthook/husky with configurable skip lists
(`gitHooksEnabled`, `gitHooksSkipList`)
Also removes all `orchestrator-develop` branch references, replacing with `main`.
13 new action inputs, 13 new files, 14 new CLI provider tests, 17 submodule tests,
plus cache/LFS/hooks unit tests. All 452 tests pass.
* feat(orchestrator): add experimental GCP Cloud Run and Azure ACI providers
Add two new cloud provider implementations for the orchestrator, both marked
as experimental:
- **GCP Cloud Run Jobs** (`providerStrategy: gcp-cloud-run`): Executes Unity
builds as Cloud Run Jobs with GCS FUSE for large artifact storage. Supports
configurable machine types, service accounts, and VPC connectors. 7 new inputs
(gcpProject, gcpRegion, gcpBucket, gcpMachineType, gcpDiskSizeGb,
gcpServiceAccount, gcpVpcConnector).
- **Azure Container Instances** (`providerStrategy: azure-aci`): Executes Unity
builds as ACI containers with Azure File Shares (Premium FileStorage) for
large artifact storage up to 100 TiB. Supports configurable CPU/memory,
VNet integration, and subscription targeting. 9 new inputs
(azureResourceGroup, azureLocation, azureStorageAccount, azureFileShareName,
azureSubscriptionId, azureCpu, azureMemoryGb, azureDiskSizeGb, azureSubnetId).
Both providers use their respective CLIs (gcloud, az) for infrastructure
management and support garbage collection of old build resources. No tests
included as these require real cloud infrastructure to validate.
* feat(orchestrator): multi-storage support for GCP and Azure providers
Both providers now support four storage backends via gcpStorageType / azureStorageType:
GCP Cloud Run:
- gcs-fuse: Mount GCS bucket as POSIX filesystem (unlimited, best for large sequential I/O)
- gcs-copy: Copy artifacts in/out via gsutil (simpler, no FUSE overhead)
- nfs: Filestore NFS mount (true POSIX, good random I/O, up to 100 TiB)
- in-memory: tmpfs (fastest, volatile, up to 32 GiB)
Azure ACI:
- azure-files: SMB file share mount (up to 100 TiB, premium throughput)
- blob-copy: Copy artifacts in/out via az storage blob (no mount overhead)
- azure-files-nfs: NFS 4.1 file share mount (true POSIX, no SMB lock overhead)
- in-memory: emptyDir tmpfs (fastest, volatile, limited by container memory)
New inputs: gcpStorageType, gcpFilestoreIp, gcpFilestoreShare, azureStorageType,
azureBlobContainer. Constructor validates storage config and warns on missing
prerequisites (e.g. NFS requires VPC connector/subnet).
* feat(orchestrator): automatic provider fallback with runner availability check
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.
* feat(orchestrator): add retry-on-fallback and provider init timeout
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.
* style: format changed files with prettier
* test(orchestrator): expand local cache service test coverage
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.
* test(orchestrator): add runner availability service tests
Covers: no token skip, no runners fallback, busy/offline runners,
label filtering (case-insensitive), minAvailable threshold,
fail-open on API error, mixed runner states.
* test(orchestrator): add unit tests for untested core services
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).
* ci(orchestrator): add fast unit test gate to integrity workflow
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.
* test(orchestrator): expand unit tests for enterprise services
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.
* fix(orchestrator): use http.extraHeader for secure git authentication
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
* feat(orchestrator): add premade secret sources and YAML definitions
Add SecretSourceService with premade secret source integrations:
- aws-secrets-manager (with --query SecretString for direct value)
- aws-parameter-store (with --with-decryption)
- gcp-secret-manager (latest version)
- azure-key-vault (via $AZURE_VAULT_NAME env var)
- env (environment variables, no shell command needed)
- Custom commands (any string with {0} placeholder)
- YAML file definitions for custom sources
Add secretSource input that takes precedence over inputPullCommand.
Backward compatible — existing inputPullCommand behavior unchanged.
Closes #776
* feat(secrets): add HashiCorp Vault as first-class premade secret source
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
* feat(lfs): add built-in elastic-git-storage support with auto-install
First-class support for elastic-git-storage as a custom LFS transfer
agent. When lfsTransferAgent is set to "elastic-git-storage" (or
"elastic-git-storage@v1.0.0" 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.
* feat(hooks): add Unity Git Hooks integration and runHookGroups
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.
* feat(orchestrator): add test workflow engine placeholder
Initial scaffold for the test workflow engine service directory.
* feat(orchestrator): add hot runner protocol placeholder
Initial scaffold for the runner registration and hot editor provider module.
* feat(orchestrator): generic artifact system — output types, manifests, and collection service
* feat(orchestrator): incremental sync protocol — git delta, direct input, and storage-backed sync
* feat: community plugin validation workflow (#800)
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
* feat(orchestrator): CI platform providers — Remote PowerShell, GitHub Actions, GitLab CI, Ansible
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.
* style: fix prettier formatting and eslint errors on test files
* feat(orchestrator): build reliability features — git integrity, reserved filename cleanup, archival
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.
* feat(reliability): implement build reliability service with git integrity, reserved filename cleanup, and build archival
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.
* test(providers): add comprehensive unit tests for GitHub Actions, GitLab CI, PowerShell, and Ansible providers (#806)
* feat(hot-runner): implement hot runner protocol with registry, health monitoring, and job dispatch (#791)
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
* feat(artifacts): complete generic artifact system with upload handlers, tests, and action integration (#798)
- 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
* feat(testing): implement test workflow engine with YAML suites, taxonomy filtering, and structured results (#790)
* feat(sync): complete incremental sync protocol with storage-pull, state management, and tests (#799)
- 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
* feat(cache): add child workspace isolation for multi-product CI builds (#777)
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.
* fix(testing): use async exec for parallel test group execution
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).
* fix(cli-provider): add timeout protection for external CLI processes
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
* fix(secrets): prevent shell injection in secret key names and mask values
- 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
* chore: rebuild dist for cli-provider timeout changes
* fix(artifacts): validate rclone availability before storage upload
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.
* fix(load-balancing): add pagination limits and rate-limit detection
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).
* fix(reliability): add disk space validation before build archival
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.
* fix(hot-runner): validate persisted registry state and add dispatcher safeguards
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.
* fix(providers): add polling timeouts, fix credential parsing, validate dependencies
- 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
* chore: rebuild dist for provider timeout and credential fixes
* fix: prettier formatting for orchestrator-folders-auth test
* ci: split orchestrator integrity into parallel jobs for faster validation
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
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* feat: add official game-ci CLI with build, activate, and orchestrate commands
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
* feat(cli): add npm publish workflow and CLI tests
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
* feat(cli): add release workflow, install scripts, and self-update command
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.
* fix(cli): address review findings — exit codes, missing inputs, null safety
- Add process.exit(1) in cli.ts catch block so failures produce non-zero exit codes
- Add 6 missing build inputs: containerRegistryRepository, containerRegistryImageVersion,
dockerIsolationMode, sshPublicKeysDirectoryPath, cacheUnityInstallationOnMac, unityHubVersionOnMac
- Add 6 missing orchestrate inputs: kubeStorageClass, readInputFromOverrideList,
readInputOverrideCommand, postBuildSteps, preBuildSteps, customJob
- Fix activate command description to accurately reflect verification behavior
- Add null check before accessing result.BuildResults in orchestrate handler
* ci: split orchestrator integrity into 4 parallel jobs to fix timeout
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.
* chore: add integration branch update scripts for release/lts-2.0.0
* ci: set macOS builds to continue-on-error
* chore: add release/lts-infrastructure to update-all script
* ci: set macOS builds to continue-on-error
* fix: make git hooks opt-in only — do not modify hooks when disabled
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.
* test: add integration wiring and input parsing tests for enterprise features
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.
* ci: mark failed macOS builds as neutral instead of failure
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.
* revert: restore build-tests-mac.yml to match main
Stop modifying the macOS build workflow — leave it identical to main.
* fix(test): add gitAuthMode to orchestrator-folders test mock
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.
* fix(ci): bump node version to 20 in integrity-check
yargs@18.0.0 requires Node >=20.19.0, so Node 18 is no longer
compatible.
* fix: downgrade yargs to ^17.7.2 and revert Node to 18 for CI compatibility
yargs@18 requires Node >=20.19.0 which is incompatible with CI's Node 18.
* refactor(cli): move cache command under orchestrate subcommand
Cache is an orchestrator feature, so it belongs under `game-ci orchestrate cache`
rather than as a top-level `game-ci cache` command.
* ci: add orchestrator compatibility validation workflow
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
* refactor: route orchestrator through plugin loader
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.
* refactor: extract orchestrator — delete 30k lines, decouple all imports
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.
* refactor: move CLI to orchestrator, fix validate-orchestrator workflow
- 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.
* fix(ci): remove reference to deleted orchestrator-integrity.yml
The orchestrator job in integrity-check.yml called the deleted
orchestrator-integrity.yml workflow, causing CI failure.
* fix(ci): use --legacy-peer-deps for orchestrator install in validation
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.
* chore: remove temporary delete-me scripts
* feat(ci): add orchestrator integration tests and plugin interface tests
- 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)
* fix(ci): add build step to k8s and aws integration jobs
The orchestrator tests need compiled output (dist/index.js) to exist
before running integration tests that spawn containers/k8s jobs.
* fix(ci): add refactor/** branch pattern and workflow_dispatch to orchestrator workflows
The refactor/orchestrator-extraction branch was not matching the
feature/** pattern, preventing the integration workflow from running
after fix commits were pushed.
* refactor(ci): split orchestrator tests into per-PR health checks and nightly exhaustive suite
validate-orchestrator.yml (per-PR, ~5 min):
- Plugin architecture health: compilation, unit tests, plugin loader
graceful degradation, installed service validation, type declaration checks
validate-orchestrator-integration.yml (daily 3 AM UTC cron, ~1-2h):
- 5 parallel jobs mirroring orchestrator-integrity.yml:
plugin-interface, k8s (5 tests), aws (10 tests),
local-docker (9 tests), rclone (1 test)
- Full LocalStack + k3d integration coverage
- continue-on-error on known flaky end2end tests
* ci: add yarn.lock to validate-orchestrator path filters
Ensure orchestrator validation runs when yarn.lock changes, since
dependency updates can affect plugin compatibility.
* refactor: move install scripts to orchestrator repo
Install scripts now live at game-ci/orchestrator where the CLI releases
are published. Removed from unity-builder to avoid duplication.
* Potential fix for code scanning alert no. 78: Workflow does not contain permissions
* refactor: rename enterprise services to plugin services
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.
* fix(ci): update workflow references from loadEnterpriseServices to loadPluginServices
CI workflows still referenced the old function name after the rename.
* ci: remove (Nightly) from integration tests workflow name
* fix: only suppress module-not-found errors in plugin loader
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.
* ci: add smoke test for orchestrator build wiring
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.
* ci: wire orchestrator integration tests into integrity check
- 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
* fix(ci): pin LocalStack to v3.8.1 for AWS SDK v3 compatibility
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.
* revert: restore localstack:latest now that SDK is pinned
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.
* ci: reorder AWS integration tests to prevent workspace corruption
Move mandatory tests (caching, locking-core, locking-get-locked) before
continue-on-error e2e tests. The e2e tests can corrupt the workspace
(delete package.json), which was causing subsequent mandatory tests to
fail with "Couldn't find a package.json".
* refactor: plugin lifecycle interface for orchestrator extraction
Replace hardcoded orchestrator params with a lifecycle-based plugin
interface. The orchestrator reads its own config from env vars —
unity-builder just calls 6 hooks (initialize, canHandleBuild,
handleBuild, beforeLocalBuild, afterLocalBuild, handlePostBuild).
Removes ~2900 lines from unity-builder (93 BuildParameters fields,
346 Input getters, 70 action.yml inputs, 400 lines of service
orchestration in index.ts).
* fix: align CI workflow with actual loadOrchestratorPlugin export
The validate-orchestrator workflows referenced loadOrchestrator and
loadPluginServices which don't exist — the source exports
loadOrchestratorPlugin. Updated all CI steps to use the correct
function name and test the actual OrchestratorPlugin lifecycle interface.
* fix: checkout matching orchestrator branch in CI validation
The validate-orchestrator workflow was always checking out the main
branch of game-ci/orchestrator. When both repos have changes on a
feature branch (e.g. refactor/orchestrator-extraction), the CI needs
to use the matching branch. Falls back to main if the branch doesn't
exist in the orchestrator repo.
* ci: add run-integration label to trigger full integration tests on PRs
PRs labeled `run-integration` now run the full orchestrator integration
suite (K8s, AWS, local-docker, rclone via LocalStack + k3d). Without the
label, integration tests only run on push to main and the daily cron.
* ci: checkout matching orchestrator branch in integration tests
Try the matching branch name (e.g. refactor/orchestrator-extraction)
from game-ci/orchestrator first, falling back to main. This allows
testing cross-repo changes before merging to orchestrator main.
* ci: switch from LocalStack to MiniStack for AWS mock services
LocalStack community edition was discontinued (2026.03.0+) and now
requires a paid license for ECS, CloudFormation, Kinesis, and other
services used in integration tests.
Switch to MiniStack (MIT, free, ministackorg/ministack) which provides
all 40+ AWS services on the same port 4566 with backward-compatible
health endpoints. ~10x smaller image, ~2s startup.
* feat: add sync-secrets workflow for sibling repositories
Manually-triggered workflow that copies secrets (Unity credentials,
AWS/GCP tokens, Codecov) from unity-builder to orchestrator or cli repos.
Supports dry-run mode. Folded from PR #825.
* Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'
* fix: add UNITY_LICENSE and NPM_TOKEN to sync-secrets, don't block on failures
* chore: remove LOCALSTACK_AUTH_TOKEN from sync-secrets workflow
MiniStack doesn't require an auth token.
---------
… (#819)
* feat(orchestrator): enterprise feature support — CLI provider, submodule profiles, caching, LFS, hooks
Add generic enterprise-grade features to the orchestrator, enabling Unity projects with
complex CI/CD pipelines to adopt game-ci/unity-builder with built-in support for:
- CLI provider protocol: JSON-over-stdin/stdout bridge enabling providers in any language
(Go, Python, Rust, shell) via the `providerExecutable` input
- Submodule profiles: YAML-based selective submodule initialization with glob patterns
and variant overlays (`submoduleProfilePath`, `submoduleVariantPath`)
- Local build caching: Filesystem-based Library and LFS caching for local builds without
external cache actions (`localCacheEnabled`, `localCacheRoot`)
- Custom LFS transfer agents: Register external transfer agents like elastic-git-storage
(`lfsTransferAgent`, `lfsTransferAgentArgs`, `lfsStoragePaths`)
- Git hooks support: Detect and install lefthook/husky with configurable skip lists
(`gitHooksEnabled`, `gitHooksSkipList`)
Also removes all `orchestrator-develop` branch references, replacing with `main`.
13 new action inputs, 13 new files, 14 new CLI provider tests, 17 submodule tests,
plus cache/LFS/hooks unit tests. All 452 tests pass.
* feat(orchestrator): add experimental GCP Cloud Run and Azure ACI providers
Add two new cloud provider implementations for the orchestrator, both marked
as experimental:
- **GCP Cloud Run Jobs** (`providerStrategy: gcp-cloud-run`): Executes Unity
builds as Cloud Run Jobs with GCS FUSE for large artifact storage. Supports
configurable machine types, service accounts, and VPC connectors. 7 new inputs
(gcpProject, gcpRegion, gcpBucket, gcpMachineType, gcpDiskSizeGb,
gcpServiceAccount, gcpVpcConnector).
- **Azure Container Instances** (`providerStrategy: azure-aci`): Executes Unity
builds as ACI containers with Azure File Shares (Premium FileStorage) for
large artifact storage up to 100 TiB. Supports configurable CPU/memory,
VNet integration, and subscription targeting. 9 new inputs
(azureResourceGroup, azureLocation, azureStorageAccount, azureFileShareName,
azureSubscriptionId, azureCpu, azureMemoryGb, azureDiskSizeGb, azureSubnetId).
Both providers use their respective CLIs (gcloud, az) for infrastructure
management and support garbage collection of old build resources. No tests
included as these require real cloud infrastructure to validate.
* feat(orchestrator): multi-storage support for GCP and Azure providers
Both providers now support four storage backends via gcpStorageType / azureStorageType:
GCP Cloud Run:
- gcs-fuse: Mount GCS bucket as POSIX filesystem (unlimited, best for large sequential I/O)
- gcs-copy: Copy artifacts in/out via gsutil (simpler, no FUSE overhead)
- nfs: Filestore NFS mount (true POSIX, good random I/O, up to 100 TiB)
- in-memory: tmpfs (fastest, volatile, up to 32 GiB)
Azure ACI:
- azure-files: SMB file share mount (up to 100 TiB, premium throughput)
- blob-copy: Copy artifacts in/out via az storage blob (no mount overhead)
- azure-files-nfs: NFS 4.1 file share mount (true POSIX, no SMB lock overhead)
- in-memory: emptyDir tmpfs (fastest, volatile, limited by container memory)
New inputs: gcpStorageType, gcpFilestoreIp, gcpFilestoreShare, azureStorageType,
azureBlobContainer. Constructor validates storage config and warns on missing
prerequisites (e.g. NFS requires VPC connector/subnet).
* feat(orchestrator): automatic provider fallback with runner availability check
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.
* feat(orchestrator): add retry-on-fallback and provider init timeout
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.
* style: format changed files with prettier
* test(orchestrator): expand local cache service test coverage
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.
* test(orchestrator): add runner availability service tests
Covers: no token skip, no runners fallback, busy/offline runners,
label filtering (case-insensitive), minAvailable threshold,
fail-open on API error, mixed runner states.
* test(orchestrator): add unit tests for untested core services
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).
* ci(orchestrator): add fast unit test gate to integrity workflow
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.
* test(orchestrator): expand unit tests for enterprise services
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.
* fix(orchestrator): use http.extraHeader for secure git authentication
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
* feat(orchestrator): add premade secret sources and YAML definitions
Add SecretSourceService with premade secret source integrations:
- aws-secrets-manager (with --query SecretString for direct value)
- aws-parameter-store (with --with-decryption)
- gcp-secret-manager (latest version)
- azure-key-vault (via $AZURE_VAULT_NAME env var)
- env (environment variables, no shell command needed)
- Custom commands (any string with {0} placeholder)
- YAML file definitions for custom sources
Add secretSource input that takes precedence over inputPullCommand.
Backward compatible — existing inputPullCommand behavior unchanged.
Closes #776
* feat(secrets): add HashiCorp Vault as first-class premade secret source
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
* feat(lfs): add built-in elastic-git-storage support with auto-install
First-class support for elastic-git-storage as a custom LFS transfer
agent. When lfsTransferAgent is set to "elastic-git-storage" (or
"elastic-git-storage@v1.0.0" 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.
* feat(hooks): add Unity Git Hooks integration and runHookGroups
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.
* feat(orchestrator): add test workflow engine placeholder
Initial scaffold for the test workflow engine service directory.
* feat(orchestrator): add hot runner protocol placeholder
Initial scaffold for the runner registration and hot editor provider module.
* feat(orchestrator): generic artifact system — output types, manifests, and collection service
* feat(orchestrator): incremental sync protocol — git delta, direct input, and storage-backed sync
* feat: community plugin validation workflow (#800)
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
* feat(orchestrator): CI platform providers — Remote PowerShell, GitHub Actions, GitLab CI, Ansible
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.
* style: fix prettier formatting and eslint errors on test files
* feat(orchestrator): build reliability features — git integrity, reserved filename cleanup, archival
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.
* feat(reliability): implement build reliability service with git integrity, reserved filename cleanup, and build archival
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.
* test(providers): add comprehensive unit tests for GitHub Actions, GitLab CI, PowerShell, and Ansible providers (#806)
* feat(hot-runner): implement hot runner protocol with registry, health monitoring, and job dispatch (#791)
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
* feat(artifacts): complete generic artifact system with upload handlers, tests, and action integration (#798)
- 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
* feat(testing): implement test workflow engine with YAML suites, taxonomy filtering, and structured results (#790)
* feat(sync): complete incremental sync protocol with storage-pull, state management, and tests (#799)
- 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
* feat(cache): add child workspace isolation for multi-product CI builds (#777)
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.
* fix(testing): use async exec for parallel test group execution
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).
* fix(cli-provider): add timeout protection for external CLI processes
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
* fix(secrets): prevent shell injection in secret key names and mask values
- 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
* chore: rebuild dist for cli-provider timeout changes
* fix(artifacts): validate rclone availability before storage upload
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.
* fix(load-balancing): add pagination limits and rate-limit detection
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).
* fix(reliability): add disk space validation before build archival
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.
* fix(hot-runner): validate persisted registry state and add dispatcher safeguards
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.
* fix(providers): add polling timeouts, fix credential parsing, validate dependencies
- 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
* chore: rebuild dist for provider timeout and credential fixes
* fix: prettier formatting for orchestrator-folders-auth test
* ci: split orchestrator integrity into parallel jobs for faster validation
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
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* feat: add official game-ci CLI with build, activate, and orchestrate commands
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
* feat(cli): add npm publish workflow and CLI tests
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
* feat(cli): add release workflow, install scripts, and self-update command
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.
* fix(cli): address review findings — exit codes, missing inputs, null safety
- Add process.exit(1) in cli.ts catch block so failures produce non-zero exit codes
- Add 6 missing build inputs: containerRegistryRepository, containerRegistryImageVersion,
dockerIsolationMode, sshPublicKeysDirectoryPath, cacheUnityInstallationOnMac, unityHubVersionOnMac
- Add 6 missing orchestrate inputs: kubeStorageClass, readInputFromOverrideList,
readInputOverrideCommand, postBuildSteps, preBuildSteps, customJob
- Fix activate command description to accurately reflect verification behavior
- Add null check before accessing result.BuildResults in orchestrate handler
* ci: split orchestrator integrity into 4 parallel jobs to fix timeout
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.
* chore: add integration branch update scripts for release/lts-2.0.0
* ci: set macOS builds to continue-on-error
* chore: add release/lts-infrastructure to update-all script
* ci: set macOS builds to continue-on-error
* fix: make git hooks opt-in only — do not modify hooks when disabled
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.
* test: add integration wiring and input parsing tests for enterprise features
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.
* ci: mark failed macOS builds as neutral instead of failure
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.
* revert: restore build-tests-mac.yml to match main
Stop modifying the macOS build workflow — leave it identical to main.
* fix(test): add gitAuthMode to orchestrator-folders test mock
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.
* fix(ci): bump node version to 20 in integrity-check
yargs@18.0.0 requires Node >=20.19.0, so Node 18 is no longer
compatible.
* fix: downgrade yargs to ^17.7.2 and revert Node to 18 for CI compatibility
yargs@18 requires Node >=20.19.0 which is incompatible with CI's Node 18.
* refactor(cli): move cache command under orchestrate subcommand
Cache is an orchestrator feature, so it belongs under `game-ci orchestrate cache`
rather than as a top-level `game-ci cache` command.
* ci: add orchestrator compatibility validation workflow
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
* refactor: route orchestrator through plugin loader
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.
* refactor: extract orchestrator — delete 30k lines, decouple all imports
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.
* refactor: move CLI to orchestrator, fix validate-orchestrator workflow
- 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.
* fix(ci): remove reference to deleted orchestrator-integrity.yml
The orchestrator job in integrity-check.yml called the deleted
orchestrator-integrity.yml workflow, causing CI failure.
* fix(ci): use --legacy-peer-deps for orchestrator install in validation
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.
* chore: remove temporary delete-me scripts
* feat(ci): add orchestrator integration tests and plugin interface tests
- 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)
* fix(ci): add build step to k8s and aws integration jobs
The orchestrator tests need compiled output (dist/index.js) to exist
before running integration tests that spawn containers/k8s jobs.
* fix(ci): add refactor/** branch pattern and workflow_dispatch to orchestrator workflows
The refactor/orchestrator-extraction branch was not matching the
feature/** pattern, preventing the integration workflow from running
after fix commits were pushed.
* refactor(ci): split orchestrator tests into per-PR health checks and nightly exhaustive suite
validate-orchestrator.yml (per-PR, ~5 min):
- Plugin architecture health: compilation, unit tests, plugin loader
graceful degradation, installed service validation, type declaration checks
validate-orchestrator-integration.yml (daily 3 AM UTC cron, ~1-2h):
- 5 parallel jobs mirroring orchestrator-integrity.yml:
plugin-interface, k8s (5 tests), aws (10 tests),
local-docker (9 tests), rclone (1 test)
- Full LocalStack + k3d integration coverage
- continue-on-error on known flaky end2end tests
* ci: add yarn.lock to validate-orchestrator path filters
Ensure orchestrator validation runs when yarn.lock changes, since
dependency updates can affect plugin compatibility.
* refactor: move install scripts to orchestrator repo
Install scripts now live at game-ci/orchestrator where the CLI releases
are published. Removed from unity-builder to avoid duplication.
* Potential fix for code scanning alert no. 78: Workflow does not contain permissions
* refactor: rename enterprise services to plugin services
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.
* fix(ci): update workflow references from loadEnterpriseServices to loadPluginServices
CI workflows still referenced the old function name after the rename.
* ci: remove (Nightly) from integration tests workflow name
* fix: only suppress module-not-found errors in plugin loader
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.
* ci: add smoke test for orchestrator build wiring
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.
* ci: wire orchestrator integration tests into integrity check
- 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
* fix(ci): pin LocalStack to v3.8.1 for AWS SDK v3 compatibility
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.
* revert: restore localstack:latest now that SDK is pinned
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.
* ci: reorder AWS integration tests to prevent workspace corruption
Move mandatory tests (caching, locking-core, locking-get-locked) before
continue-on-error e2e tests. The e2e tests can corrupt the workspace
(delete package.json), which was causing subsequent mandatory tests to
fail with "Couldn't find a package.json".
* refactor: plugin lifecycle interface for orchestrator extraction
Replace hardcoded orchestrator params with a lifecycle-based plugin
interface. The orchestrator reads its own config from env vars —
unity-builder just calls 6 hooks (initialize, canHandleBuild,
handleBuild, beforeLocalBuild, afterLocalBuild, handlePostBuild).
Removes ~2900 lines from unity-builder (93 BuildParameters fields,
346 Input getters, 70 action.yml inputs, 400 lines of service
orchestration in index.ts).
* fix: align CI workflow with actual loadOrchestratorPlugin export
The validate-orchestrator workflows referenced loadOrchestrator and
loadPluginServices which don't exist — the source exports
loadOrchestratorPlugin. Updated all CI steps to use the correct
function name and test the actual OrchestratorPlugin lifecycle interface.
* fix: checkout matching orchestrator branch in CI validation
The validate-orchestrator workflow was always checking out the main
branch of game-ci/orchestrator. When both repos have changes on a
feature branch (e.g. refactor/orchestrator-extraction), the CI needs
to use the matching branch. Falls back to main if the branch doesn't
exist in the orchestrator repo.
* ci: add run-integration label to trigger full integration tests on PRs
PRs labeled `run-integration` now run the full orchestrator integration
suite (K8s, AWS, local-docker, rclone via LocalStack + k3d). Without the
label, integration tests only run on push to main and the daily cron.
* ci: checkout matching orchestrator branch in integration tests
Try the matching branch name (e.g. refactor/orchestrator-extraction)
from game-ci/orchestrator first, falling back to main. This allows
testing cross-repo changes before merging to orchestrator main.
* ci: switch from LocalStack to MiniStack for AWS mock services
LocalStack community edition was discontinued (2026.03.0+) and now
requires a paid license for ECS, CloudFormation, Kinesis, and other
services used in integration tests.
Switch to MiniStack (MIT, free, ministackorg/ministack) which provides
all 40+ AWS services on the same port 4566 with backward-compatible
health endpoints. ~10x smaller image, ~2s startup.
* feat: add sync-secrets workflow for sibling repositories
Manually-triggered workflow that copies secrets (Unity credentials,
AWS/GCP tokens, Codecov) from unity-builder to orchestrator or cli repos.
Supports dry-run mode. Folded from PR #825.
* Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'
* fix: add UNITY_LICENSE and NPM_TOKEN to sync-secrets, don't block on failures
* chore: remove LOCALSTACK_AUTH_TOKEN from sync-secrets workflow
MiniStack doesn't require an auth token.
---------
… (#819)
* feat(orchestrator): enterprise feature support — CLI provider, submodule profiles, caching, LFS, hooks
Add generic enterprise-grade features to the orchestrator, enabling Unity projects with
complex CI/CD pipelines to adopt game-ci/unity-builder with built-in support for:
- CLI provider protocol: JSON-over-stdin/stdout bridge enabling providers in any language
(Go, Python, Rust, shell) via the `providerExecutable` input
- Submodule profiles: YAML-based selective submodule initialization with glob patterns
and variant overlays (`submoduleProfilePath`, `submoduleVariantPath`)
- Local build caching: Filesystem-based Library and LFS caching for local builds without
external cache actions (`localCacheEnabled`, `localCacheRoot`)
- Custom LFS transfer agents: Register external transfer agents like elastic-git-storage
(`lfsTransferAgent`, `lfsTransferAgentArgs`, `lfsStoragePaths`)
- Git hooks support: Detect and install lefthook/husky with configurable skip lists
(`gitHooksEnabled`, `gitHooksSkipList`)
Also removes all `orchestrator-develop` branch references, replacing with `main`.
13 new action inputs, 13 new files, 14 new CLI provider tests, 17 submodule tests,
plus cache/LFS/hooks unit tests. All 452 tests pass.
* feat(orchestrator): add experimental GCP Cloud Run and Azure ACI providers
Add two new cloud provider implementations for the orchestrator, both marked
as experimental:
- **GCP Cloud Run Jobs** (`providerStrategy: gcp-cloud-run`): Executes Unity
builds as Cloud Run Jobs with GCS FUSE for large artifact storage. Supports
configurable machine types, service accounts, and VPC connectors. 7 new inputs
(gcpProject, gcpRegion, gcpBucket, gcpMachineType, gcpDiskSizeGb,
gcpServiceAccount, gcpVpcConnector).
- **Azure Container Instances** (`providerStrategy: azure-aci`): Executes Unity
builds as ACI containers with Azure File Shares (Premium FileStorage) for
large artifact storage up to 100 TiB. Supports configurable CPU/memory,
VNet integration, and subscription targeting. 9 new inputs
(azureResourceGroup, azureLocation, azureStorageAccount, azureFileShareName,
azureSubscriptionId, azureCpu, azureMemoryGb, azureDiskSizeGb, azureSubnetId).
Both providers use their respective CLIs (gcloud, az) for infrastructure
management and support garbage collection of old build resources. No tests
included as these require real cloud infrastructure to validate.
* feat(orchestrator): multi-storage support for GCP and Azure providers
Both providers now support four storage backends via gcpStorageType / azureStorageType:
GCP Cloud Run:
- gcs-fuse: Mount GCS bucket as POSIX filesystem (unlimited, best for large sequential I/O)
- gcs-copy: Copy artifacts in/out via gsutil (simpler, no FUSE overhead)
- nfs: Filestore NFS mount (true POSIX, good random I/O, up to 100 TiB)
- in-memory: tmpfs (fastest, volatile, up to 32 GiB)
Azure ACI:
- azure-files: SMB file share mount (up to 100 TiB, premium throughput)
- blob-copy: Copy artifacts in/out via az storage blob (no mount overhead)
- azure-files-nfs: NFS 4.1 file share mount (true POSIX, no SMB lock overhead)
- in-memory: emptyDir tmpfs (fastest, volatile, limited by container memory)
New inputs: gcpStorageType, gcpFilestoreIp, gcpFilestoreShare, azureStorageType,
azureBlobContainer. Constructor validates storage config and warns on missing
prerequisites (e.g. NFS requires VPC connector/subnet).
* feat(orchestrator): automatic provider fallback with runner availability check
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.
* feat(orchestrator): add retry-on-fallback and provider init timeout
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.
* style: format changed files with prettier
* test(orchestrator): expand local cache service test coverage
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.
* test(orchestrator): add runner availability service tests
Covers: no token skip, no runners fallback, busy/offline runners,
label filtering (case-insensitive), minAvailable threshold,
fail-open on API error, mixed runner states.
* test(orchestrator): add unit tests for untested core services
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).
* ci(orchestrator): add fast unit test gate to integrity workflow
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.
* test(orchestrator): expand unit tests for enterprise services
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.
* fix(orchestrator): use http.extraHeader for secure git authentication
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
* feat(orchestrator): add premade secret sources and YAML definitions
Add SecretSourceService with premade secret source integrations:
- aws-secrets-manager (with --query SecretString for direct value)
- aws-parameter-store (with --with-decryption)
- gcp-secret-manager (latest version)
- azure-key-vault (via $AZURE_VAULT_NAME env var)
- env (environment variables, no shell command needed)
- Custom commands (any string with {0} placeholder)
- YAML file definitions for custom sources
Add secretSource input that takes precedence over inputPullCommand.
Backward compatible — existing inputPullCommand behavior unchanged.
Closes #776
* feat(secrets): add HashiCorp Vault as first-class premade secret source
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
* feat(lfs): add built-in elastic-git-storage support with auto-install
First-class support for elastic-git-storage as a custom LFS transfer
agent. When lfsTransferAgent is set to "elastic-git-storage" (or
"elastic-git-storage@v1.0.0" 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.
* feat(hooks): add Unity Git Hooks integration and runHookGroups
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.
* feat(orchestrator): add test workflow engine placeholder
Initial scaffold for the test workflow engine service directory.
* feat(orchestrator): add hot runner protocol placeholder
Initial scaffold for the runner registration and hot editor provider module.
* feat(orchestrator): generic artifact system — output types, manifests, and collection service
* feat(orchestrator): incremental sync protocol — git delta, direct input, and storage-backed sync
* feat: community plugin validation workflow (#800)
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
* feat(orchestrator): CI platform providers — Remote PowerShell, GitHub Actions, GitLab CI, Ansible
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.
* style: fix prettier formatting and eslint errors on test files
* feat(orchestrator): build reliability features — git integrity, reserved filename cleanup, archival
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.
* feat(reliability): implement build reliability service with git integrity, reserved filename cleanup, and build archival
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.
* test(providers): add comprehensive unit tests for GitHub Actions, GitLab CI, PowerShell, and Ansible providers (#806)
* feat(hot-runner): implement hot runner protocol with registry, health monitoring, and job dispatch (#791)
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
* feat(artifacts): complete generic artifact system with upload handlers, tests, and action integration (#798)
- 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
* feat(testing): implement test workflow engine with YAML suites, taxonomy filtering, and structured results (#790)
* feat(sync): complete incremental sync protocol with storage-pull, state management, and tests (#799)
- 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
* feat(cache): add child workspace isolation for multi-product CI builds (#777)
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.
* fix(testing): use async exec for parallel test group execution
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).
* fix(cli-provider): add timeout protection for external CLI processes
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
* fix(secrets): prevent shell injection in secret key names and mask values
- 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
* chore: rebuild dist for cli-provider timeout changes
* fix(artifacts): validate rclone availability before storage upload
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.
* fix(load-balancing): add pagination limits and rate-limit detection
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).
* fix(reliability): add disk space validation before build archival
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.
* fix(hot-runner): validate persisted registry state and add dispatcher safeguards
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.
* fix(providers): add polling timeouts, fix credential parsing, validate dependencies
- 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
* chore: rebuild dist for provider timeout and credential fixes
* fix: prettier formatting for orchestrator-folders-auth test
* ci: split orchestrator integrity into parallel jobs for faster validation
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
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* feat: add official game-ci CLI with build, activate, and orchestrate commands
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
* feat(cli): add npm publish workflow and CLI tests
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
* feat(cli): add release workflow, install scripts, and self-update command
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.
* fix(cli): address review findings — exit codes, missing inputs, null safety
- Add process.exit(1) in cli.ts catch block so failures produce non-zero exit codes
- Add 6 missing build inputs: containerRegistryRepository, containerRegistryImageVersion,
dockerIsolationMode, sshPublicKeysDirectoryPath, cacheUnityInstallationOnMac, unityHubVersionOnMac
- Add 6 missing orchestrate inputs: kubeStorageClass, readInputFromOverrideList,
readInputOverrideCommand, postBuildSteps, preBuildSteps, customJob
- Fix activate command description to accurately reflect verification behavior
- Add null check before accessing result.BuildResults in orchestrate handler
* ci: split orchestrator integrity into 4 parallel jobs to fix timeout
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.
* chore: add integration branch update scripts for release/lts-2.0.0
* ci: set macOS builds to continue-on-error
* chore: add release/lts-infrastructure to update-all script
* ci: set macOS builds to continue-on-error
* fix: make git hooks opt-in only — do not modify hooks when disabled
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.
* test: add integration wiring and input parsing tests for enterprise features
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.
* ci: mark failed macOS builds as neutral instead of failure
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.
* revert: restore build-tests-mac.yml to match main
Stop modifying the macOS build workflow — leave it identical to main.
* fix(test): add gitAuthMode to orchestrator-folders test mock
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.
* fix(ci): bump node version to 20 in integrity-check
yargs@18.0.0 requires Node >=20.19.0, so Node 18 is no longer
compatible.
* fix: downgrade yargs to ^17.7.2 and revert Node to 18 for CI compatibility
yargs@18 requires Node >=20.19.0 which is incompatible with CI's Node 18.
* refactor(cli): move cache command under orchestrate subcommand
Cache is an orchestrator feature, so it belongs under `game-ci orchestrate cache`
rather than as a top-level `game-ci cache` command.
* ci: add orchestrator compatibility validation workflow
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
* refactor: route orchestrator through plugin loader
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.
* refactor: extract orchestrator — delete 30k lines, decouple all imports
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.
* refactor: move CLI to orchestrator, fix validate-orchestrator workflow
- 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.
* fix(ci): remove reference to deleted orchestrator-integrity.yml
The orchestrator job in integrity-check.yml called the deleted
orchestrator-integrity.yml workflow, causing CI failure.
* fix(ci): use --legacy-peer-deps for orchestrator install in validation
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.
* chore: remove temporary delete-me scripts
* feat(ci): add orchestrator integration tests and plugin interface tests
- 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)
* fix(ci): add build step to k8s and aws integration jobs
The orchestrator tests need compiled output (dist/index.js) to exist
before running integration tests that spawn containers/k8s jobs.
* fix(ci): add refactor/** branch pattern and workflow_dispatch to orchestrator workflows
The refactor/orchestrator-extraction branch was not matching the
feature/** pattern, preventing the integration workflow from running
after fix commits were pushed.
* refactor(ci): split orchestrator tests into per-PR health checks and nightly exhaustive suite
validate-orchestrator.yml (per-PR, ~5 min):
- Plugin architecture health: compilation, unit tests, plugin loader
graceful degradation, installed service validation, type declaration checks
validate-orchestrator-integration.yml (daily 3 AM UTC cron, ~1-2h):
- 5 parallel jobs mirroring orchestrator-integrity.yml:
plugin-interface, k8s (5 tests), aws (10 tests),
local-docker (9 tests), rclone (1 test)
- Full LocalStack + k3d integration coverage
- continue-on-error on known flaky end2end tests
* ci: add yarn.lock to validate-orchestrator path filters
Ensure orchestrator validation runs when yarn.lock changes, since
dependency updates can affect plugin compatibility.
* refactor: move install scripts to orchestrator repo
Install scripts now live at game-ci/orchestrator where the CLI releases
are published. Removed from unity-builder to avoid duplication.
* Potential fix for code scanning alert no. 78: Workflow does not contain permissions
* refactor: rename enterprise services to plugin services
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.
* fix(ci): update workflow references from loadEnterpriseServices to loadPluginServices
CI workflows still referenced the old function name after the rename.
* ci: remove (Nightly) from integration tests workflow name
* fix: only suppress module-not-found errors in plugin loader
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.
* ci: add smoke test for orchestrator build wiring
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.
* ci: wire orchestrator integration tests into integrity check
- 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
* fix(ci): pin LocalStack to v3.8.1 for AWS SDK v3 compatibility
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.
* revert: restore localstack:latest now that SDK is pinned
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.
* ci: reorder AWS integration tests to prevent workspace corruption
Move mandatory tests (caching, locking-core, locking-get-locked) before
continue-on-error e2e tests. The e2e tests can corrupt the workspace
(delete package.json), which was causing subsequent mandatory tests to
fail with "Couldn't find a package.json".
* refactor: plugin lifecycle interface for orchestrator extraction
Replace hardcoded orchestrator params with a lifecycle-based plugin
interface. The orchestrator reads its own config from env vars —
unity-builder just calls 6 hooks (initialize, canHandleBuild,
handleBuild, beforeLocalBuild, afterLocalBuild, handlePostBuild).
Removes ~2900 lines from unity-builder (93 BuildParameters fields,
346 Input getters, 70 action.yml inputs, 400 lines of service
orchestration in index.ts).
* fix: align CI workflow with actual loadOrchestratorPlugin export
The validate-orchestrator workflows referenced loadOrchestrator and
loadPluginServices which don't exist — the source exports
loadOrchestratorPlugin. Updated all CI steps to use the correct
function name and test the actual OrchestratorPlugin lifecycle interface.
* fix: checkout matching orchestrator branch in CI validation
The validate-orchestrator workflow was always checking out the main
branch of game-ci/orchestrator. When both repos have changes on a
feature branch (e.g. refactor/orchestrator-extraction), the CI needs
to use the matching branch. Falls back to main if the branch doesn't
exist in the orchestrator repo.
* ci: add run-integration label to trigger full integration tests on PRs
PRs labeled `run-integration` now run the full orchestrator integration
suite (K8s, AWS, local-docker, rclone via LocalStack + k3d). Without the
label, integration tests only run on push to main and the daily cron.
* ci: checkout matching orchestrator branch in integration tests
Try the matching branch name (e.g. refactor/orchestrator-extraction)
from game-ci/orchestrator first, falling back to main. This allows
testing cross-repo changes before merging to orchestrator main.
* ci: switch from LocalStack to MiniStack for AWS mock services
LocalStack community edition was discontinued (2026.03.0+) and now
requires a paid license for ECS, CloudFormation, Kinesis, and other
services used in integration tests.
Switch to MiniStack (MIT, free, ministackorg/ministack) which provides
all 40+ AWS services on the same port 4566 with backward-compatible
health endpoints. ~10x smaller image, ~2s startup.
* feat: add sync-secrets workflow for sibling repositories
Manually-triggered workflow that copies secrets (Unity credentials,
AWS/GCP tokens, Codecov) from unity-builder to orchestrator or cli repos.
Supports dry-run mode. Folded from PR #825.
* Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'
* fix: add UNITY_LICENSE and NPM_TOKEN to sync-secrets, don't block on failures
* chore: remove LOCALSTACK_AUTH_TOKEN from sync-secrets workflow
MiniStack doesn't require an auth token.
---------
… (#819)
* feat(orchestrator): enterprise feature support — CLI provider, submodule profiles, caching, LFS, hooks
Add generic enterprise-grade features to the orchestrator, enabling Unity projects with
complex CI/CD pipelines to adopt game-ci/unity-builder with built-in support for:
- CLI provider protocol: JSON-over-stdin/stdout bridge enabling providers in any language
(Go, Python, Rust, shell) via the `providerExecutable` input
- Submodule profiles: YAML-based selective submodule initialization with glob patterns
and variant overlays (`submoduleProfilePath`, `submoduleVariantPath`)
- Local build caching: Filesystem-based Library and LFS caching for local builds without
external cache actions (`localCacheEnabled`, `localCacheRoot`)
- Custom LFS transfer agents: Register external transfer agents like elastic-git-storage
(`lfsTransferAgent`, `lfsTransferAgentArgs`, `lfsStoragePaths`)
- Git hooks support: Detect and install lefthook/husky with configurable skip lists
(`gitHooksEnabled`, `gitHooksSkipList`)
Also removes all `orchestrator-develop` branch references, replacing with `main`.
13 new action inputs, 13 new files, 14 new CLI provider tests, 17 submodule tests,
plus cache/LFS/hooks unit tests. All 452 tests pass.
* feat(orchestrator): add experimental GCP Cloud Run and Azure ACI providers
Add two new cloud provider implementations for the orchestrator, both marked
as experimental:
- **GCP Cloud Run Jobs** (`providerStrategy: gcp-cloud-run`): Executes Unity
builds as Cloud Run Jobs with GCS FUSE for large artifact storage. Supports
configurable machine types, service accounts, and VPC connectors. 7 new inputs
(gcpProject, gcpRegion, gcpBucket, gcpMachineType, gcpDiskSizeGb,
gcpServiceAccount, gcpVpcConnector).
- **Azure Container Instances** (`providerStrategy: azure-aci`): Executes Unity
builds as ACI containers with Azure File Shares (Premium FileStorage) for
large artifact storage up to 100 TiB. Supports configurable CPU/memory,
VNet integration, and subscription targeting. 9 new inputs
(azureResourceGroup, azureLocation, azureStorageAccount, azureFileShareName,
azureSubscriptionId, azureCpu, azureMemoryGb, azureDiskSizeGb, azureSubnetId).
Both providers use their respective CLIs (gcloud, az) for infrastructure
management and support garbage collection of old build resources. No tests
included as these require real cloud infrastructure to validate.
* feat(orchestrator): multi-storage support for GCP and Azure providers
Both providers now support four storage backends via gcpStorageType / azureStorageType:
GCP Cloud Run:
- gcs-fuse: Mount GCS bucket as POSIX filesystem (unlimited, best for large sequential I/O)
- gcs-copy: Copy artifacts in/out via gsutil (simpler, no FUSE overhead)
- nfs: Filestore NFS mount (true POSIX, good random I/O, up to 100 TiB)
- in-memory: tmpfs (fastest, volatile, up to 32 GiB)
Azure ACI:
- azure-files: SMB file share mount (up to 100 TiB, premium throughput)
- blob-copy: Copy artifacts in/out via az storage blob (no mount overhead)
- azure-files-nfs: NFS 4.1 file share mount (true POSIX, no SMB lock overhead)
- in-memory: emptyDir tmpfs (fastest, volatile, limited by container memory)
New inputs: gcpStorageType, gcpFilestoreIp, gcpFilestoreShare, azureStorageType,
azureBlobContainer. Constructor validates storage config and warns on missing
prerequisites (e.g. NFS requires VPC connector/subnet).
* feat(orchestrator): automatic provider fallback with runner availability check
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.
* feat(orchestrator): add retry-on-fallback and provider init timeout
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.
* style: format changed files with prettier
* test(orchestrator): expand local cache service test coverage
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.
* test(orchestrator): add runner availability service tests
Covers: no token skip, no runners fallback, busy/offline runners,
label filtering (case-insensitive), minAvailable threshold,
fail-open on API error, mixed runner states.
* test(orchestrator): add unit tests for untested core services
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).
* ci(orchestrator): add fast unit test gate to integrity workflow
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.
* test(orchestrator): expand unit tests for enterprise services
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.
* fix(orchestrator): use http.extraHeader for secure git authentication
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
* feat(orchestrator): add premade secret sources and YAML definitions
Add SecretSourceService with premade secret source integrations:
- aws-secrets-manager (with --query SecretString for direct value)
- aws-parameter-store (with --with-decryption)
- gcp-secret-manager (latest version)
- azure-key-vault (via $AZURE_VAULT_NAME env var)
- env (environment variables, no shell command needed)
- Custom commands (any string with {0} placeholder)
- YAML file definitions for custom sources
Add secretSource input that takes precedence over inputPullCommand.
Backward compatible — existing inputPullCommand behavior unchanged.
Closes #776
* feat(secrets): add HashiCorp Vault as first-class premade secret source
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
* feat(lfs): add built-in elastic-git-storage support with auto-install
First-class support for elastic-git-storage as a custom LFS transfer
agent. When lfsTransferAgent is set to "elastic-git-storage" (or
"elastic-git-storage@v1.0.0" 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.
* feat(hooks): add Unity Git Hooks integration and runHookGroups
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.
* feat(orchestrator): add test workflow engine placeholder
Initial scaffold for the test workflow engine service directory.
* feat(orchestrator): add hot runner protocol placeholder
Initial scaffold for the runner registration and hot editor provider module.
* feat(orchestrator): generic artifact system — output types, manifests, and collection service
* feat(orchestrator): incremental sync protocol — git delta, direct input, and storage-backed sync
* feat: community plugin validation workflow (#800)
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
* feat(orchestrator): CI platform providers — Remote PowerShell, GitHub Actions, GitLab CI, Ansible
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.
* style: fix prettier formatting and eslint errors on test files
* feat(orchestrator): build reliability features — git integrity, reserved filename cleanup, archival
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.
* feat(reliability): implement build reliability service with git integrity, reserved filename cleanup, and build archival
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.
* test(providers): add comprehensive unit tests for GitHub Actions, GitLab CI, PowerShell, and Ansible providers (#806)
* feat(hot-runner): implement hot runner protocol with registry, health monitoring, and job dispatch (#791)
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
* feat(artifacts): complete generic artifact system with upload handlers, tests, and action integration (#798)
- 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
* feat(testing): implement test workflow engine with YAML suites, taxonomy filtering, and structured results (#790)
* feat(sync): complete incremental sync protocol with storage-pull, state management, and tests (#799)
- 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
* feat(cache): add child workspace isolation for multi-product CI builds (#777)
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.
* fix(testing): use async exec for parallel test group execution
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).
* fix(cli-provider): add timeout protection for external CLI processes
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
* fix(secrets): prevent shell injection in secret key names and mask values
- 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
* chore: rebuild dist for cli-provider timeout changes
* fix(artifacts): validate rclone availability before storage upload
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.
* fix(load-balancing): add pagination limits and rate-limit detection
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).
* fix(reliability): add disk space validation before build archival
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.
* fix(hot-runner): validate persisted registry state and add dispatcher safeguards
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.
* fix(providers): add polling timeouts, fix credential parsing, validate dependencies
- 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
* chore: rebuild dist for provider timeout and credential fixes
* fix: prettier formatting for orchestrator-folders-auth test
* ci: split orchestrator integrity into parallel jobs for faster validation
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
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* feat: add official game-ci CLI with build, activate, and orchestrate commands
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
* feat(cli): add npm publish workflow and CLI tests
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
* feat(cli): add release workflow, install scripts, and self-update command
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.
* fix(cli): address review findings — exit codes, missing inputs, null safety
- Add process.exit(1) in cli.ts catch block so failures produce non-zero exit codes
- Add 6 missing build inputs: containerRegistryRepository, containerRegistryImageVersion,
dockerIsolationMode, sshPublicKeysDirectoryPath, cacheUnityInstallationOnMac, unityHubVersionOnMac
- Add 6 missing orchestrate inputs: kubeStorageClass, readInputFromOverrideList,
readInputOverrideCommand, postBuildSteps, preBuildSteps, customJob
- Fix activate command description to accurately reflect verification behavior
- Add null check before accessing result.BuildResults in orchestrate handler
* ci: split orchestrator integrity into 4 parallel jobs to fix timeout
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.
* chore: add integration branch update scripts for release/lts-2.0.0
* ci: set macOS builds to continue-on-error
* chore: add release/lts-infrastructure to update-all script
* ci: set macOS builds to continue-on-error
* fix: make git hooks opt-in only — do not modify hooks when disabled
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.
* test: add integration wiring and input parsing tests for enterprise features
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.
* ci: mark failed macOS builds as neutral instead of failure
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.
* revert: restore build-tests-mac.yml to match main
Stop modifying the macOS build workflow — leave it identical to main.
* fix(test): add gitAuthMode to orchestrator-folders test mock
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.
* fix(ci): bump node version to 20 in integrity-check
yargs@18.0.0 requires Node >=20.19.0, so Node 18 is no longer
compatible.
* fix: downgrade yargs to ^17.7.2 and revert Node to 18 for CI compatibility
yargs@18 requires Node >=20.19.0 which is incompatible with CI's Node 18.
* refactor(cli): move cache command under orchestrate subcommand
Cache is an orchestrator feature, so it belongs under `game-ci orchestrate cache`
rather than as a top-level `game-ci cache` command.
* ci: add orchestrator compatibility validation workflow
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
* refactor: route orchestrator through plugin loader
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.
* refactor: extract orchestrator — delete 30k lines, decouple all imports
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.
* refactor: move CLI to orchestrator, fix validate-orchestrator workflow
- 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.
* fix(ci): remove reference to deleted orchestrator-integrity.yml
The orchestrator job in integrity-check.yml called the deleted
orchestrator-integrity.yml workflow, causing CI failure.
* fix(ci): use --legacy-peer-deps for orchestrator install in validation
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.
* chore: remove temporary delete-me scripts
* feat(ci): add orchestrator integration tests and plugin interface tests
- 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)
* fix(ci): add build step to k8s and aws integration jobs
The orchestrator tests need compiled output (dist/index.js) to exist
before running integration tests that spawn containers/k8s jobs.
* fix(ci): add refactor/** branch pattern and workflow_dispatch to orchestrator workflows
The refactor/orchestrator-extraction branch was not matching the
feature/** pattern, preventing the integration workflow from running
after fix commits were pushed.
* refactor(ci): split orchestrator tests into per-PR health checks and nightly exhaustive suite
validate-orchestrator.yml (per-PR, ~5 min):
- Plugin architecture health: compilation, unit tests, plugin loader
graceful degradation, installed service validation, type declaration checks
validate-orchestrator-integration.yml (daily 3 AM UTC cron, ~1-2h):
- 5 parallel jobs mirroring orchestrator-integrity.yml:
plugin-interface, k8s (5 tests), aws (10 tests),
local-docker (9 tests), rclone (1 test)
- Full LocalStack + k3d integration coverage
- continue-on-error on known flaky end2end tests
* ci: add yarn.lock to validate-orchestrator path filters
Ensure orchestrator validation runs when yarn.lock changes, since
dependency updates can affect plugin compatibility.
* refactor: move install scripts to orchestrator repo
Install scripts now live at game-ci/orchestrator where the CLI releases
are published. Removed from unity-builder to avoid duplication.
* Potential fix for code scanning alert no. 78: Workflow does not contain permissions
* refactor: rename enterprise services to plugin services
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.
* fix(ci): update workflow references from loadEnterpriseServices to loadPluginServices
CI workflows still referenced the old function name after the rename.
* ci: remove (Nightly) from integration tests workflow name
* fix: only suppress module-not-found errors in plugin loader
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.
* ci: add smoke test for orchestrator build wiring
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.
* ci: wire orchestrator integration tests into integrity check
- 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
* fix(ci): pin LocalStack to v3.8.1 for AWS SDK v3 compatibility
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.
* revert: restore localstack:latest now that SDK is pinned
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.
* ci: reorder AWS integration tests to prevent workspace corruption
Move mandatory tests (caching, locking-core, locking-get-locked) before
continue-on-error e2e tests. The e2e tests can corrupt the workspace
(delete package.json), which was causing subsequent mandatory tests to
fail with "Couldn't find a package.json".
* refactor: plugin lifecycle interface for orchestrator extraction
Replace hardcoded orchestrator params with a lifecycle-based plugin
interface. The orchestrator reads its own config from env vars —
unity-builder just calls 6 hooks (initialize, canHandleBuild,
handleBuild, beforeLocalBuild, afterLocalBuild, handlePostBuild).
Removes ~2900 lines from unity-builder (93 BuildParameters fields,
346 Input getters, 70 action.yml inputs, 400 lines of service
orchestration in index.ts).
* fix: align CI workflow with actual loadOrchestratorPlugin export
The validate-orchestrator workflows referenced loadOrchestrator and
loadPluginServices which don't exist — the source exports
loadOrchestratorPlugin. Updated all CI steps to use the correct
function name and test the actual OrchestratorPlugin lifecycle interface.
* fix: checkout matching orchestrator branch in CI validation
The validate-orchestrator workflow was always checking out the main
branch of game-ci/orchestrator. When both repos have changes on a
feature branch (e.g. refactor/orchestrator-extraction), the CI needs
to use the matching branch. Falls back to main if the branch doesn't
exist in the orchestrator repo.
* ci: add run-integration label to trigger full integration tests on PRs
PRs labeled `run-integration` now run the full orchestrator integration
suite (K8s, AWS, local-docker, rclone via LocalStack + k3d). Without the
label, integration tests only run on push to main and the daily cron.
* ci: checkout matching orchestrator branch in integration tests
Try the matching branch name (e.g. refactor/orchestrator-extraction)
from game-ci/orchestrator first, falling back to main. This allows
testing cross-repo changes before merging to orchestrator main.
* ci: switch from LocalStack to MiniStack for AWS mock services
LocalStack community edition was discontinued (2026.03.0+) and now
requires a paid license for ECS, CloudFormation, Kinesis, and other
services used in integration tests.
Switch to MiniStack (MIT, free, ministackorg/ministack) which provides
all 40+ AWS services on the same port 4566 with backward-compatible
health endpoints. ~10x smaller image, ~2s startup.
* feat: add sync-secrets workflow for sibling repositories
Manually-triggered workflow that copies secrets (Unity credentials,
AWS/GCP tokens, Codecov) from unity-builder to orchestrator or cli repos.
Supports dry-run mode. Folded from PR #825.
* Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'
* fix: add UNITY_LICENSE and NPM_TOKEN to sync-secrets, don't block on failures
* chore: remove LOCALSTACK_AUTH_TOKEN from sync-secrets workflow
MiniStack doesn't require an auth token.
---------
… (#819)
* feat(orchestrator): enterprise feature support — CLI provider, submodule profiles, caching, LFS, hooks
Add generic enterprise-grade features to the orchestrator, enabling Unity projects with
complex CI/CD pipelines to adopt game-ci/unity-builder with built-in support for:
- CLI provider protocol: JSON-over-stdin/stdout bridge enabling providers in any language
(Go, Python, Rust, shell) via the `providerExecutable` input
- Submodule profiles: YAML-based selective submodule initialization with glob patterns
and variant overlays (`submoduleProfilePath`, `submoduleVariantPath`)
- Local build caching: Filesystem-based Library and LFS caching for local builds without
external cache actions (`localCacheEnabled`, `localCacheRoot`)
- Custom LFS transfer agents: Register external transfer agents like elastic-git-storage
(`lfsTransferAgent`, `lfsTransferAgentArgs`, `lfsStoragePaths`)
- Git hooks support: Detect and install lefthook/husky with configurable skip lists
(`gitHooksEnabled`, `gitHooksSkipList`)
Also removes all `orchestrator-develop` branch references, replacing with `main`.
13 new action inputs, 13 new files, 14 new CLI provider tests, 17 submodule tests,
plus cache/LFS/hooks unit tests. All 452 tests pass.
* feat(orchestrator): add experimental GCP Cloud Run and Azure ACI providers
Add two new cloud provider implementations for the orchestrator, both marked
as experimental:
- **GCP Cloud Run Jobs** (`providerStrategy: gcp-cloud-run`): Executes Unity
builds as Cloud Run Jobs with GCS FUSE for large artifact storage. Supports
configurable machine types, service accounts, and VPC connectors. 7 new inputs
(gcpProject, gcpRegion, gcpBucket, gcpMachineType, gcpDiskSizeGb,
gcpServiceAccount, gcpVpcConnector).
- **Azure Container Instances** (`providerStrategy: azure-aci`): Executes Unity
builds as ACI containers with Azure File Shares (Premium FileStorage) for
large artifact storage up to 100 TiB. Supports configurable CPU/memory,
VNet integration, and subscription targeting. 9 new inputs
(azureResourceGroup, azureLocation, azureStorageAccount, azureFileShareName,
azureSubscriptionId, azureCpu, azureMemoryGb, azureDiskSizeGb, azureSubnetId).
Both providers use their respective CLIs (gcloud, az) for infrastructure
management and support garbage collection of old build resources. No tests
included as these require real cloud infrastructure to validate.
* feat(orchestrator): multi-storage support for GCP and Azure providers
Both providers now support four storage backends via gcpStorageType / azureStorageType:
GCP Cloud Run:
- gcs-fuse: Mount GCS bucket as POSIX filesystem (unlimited, best for large sequential I/O)
- gcs-copy: Copy artifacts in/out via gsutil (simpler, no FUSE overhead)
- nfs: Filestore NFS mount (true POSIX, good random I/O, up to 100 TiB)
- in-memory: tmpfs (fastest, volatile, up to 32 GiB)
Azure ACI:
- azure-files: SMB file share mount (up to 100 TiB, premium throughput)
- blob-copy: Copy artifacts in/out via az storage blob (no mount overhead)
- azure-files-nfs: NFS 4.1 file share mount (true POSIX, no SMB lock overhead)
- in-memory: emptyDir tmpfs (fastest, volatile, limited by container memory)
New inputs: gcpStorageType, gcpFilestoreIp, gcpFilestoreShare, azureStorageType,
azureBlobContainer. Constructor validates storage config and warns on missing
prerequisites (e.g. NFS requires VPC connector/subnet).
* feat(orchestrator): automatic provider fallback with runner availability check
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.
* feat(orchestrator): add retry-on-fallback and provider init timeout
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.
* style: format changed files with prettier
* test(orchestrator): expand local cache service test coverage
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.
* test(orchestrator): add runner availability service tests
Covers: no token skip, no runners fallback, busy/offline runners,
label filtering (case-insensitive), minAvailable threshold,
fail-open on API error, mixed runner states.
* test(orchestrator): add unit tests for untested core services
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).
* ci(orchestrator): add fast unit test gate to integrity workflow
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.
* test(orchestrator): expand unit tests for enterprise services
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.
* fix(orchestrator): use http.extraHeader for secure git authentication
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
* feat(orchestrator): add premade secret sources and YAML definitions
Add SecretSourceService with premade secret source integrations:
- aws-secrets-manager (with --query SecretString for direct value)
- aws-parameter-store (with --with-decryption)
- gcp-secret-manager (latest version)
- azure-key-vault (via $AZURE_VAULT_NAME env var)
- env (environment variables, no shell command needed)
- Custom commands (any string with {0} placeholder)
- YAML file definitions for custom sources
Add secretSource input that takes precedence over inputPullCommand.
Backward compatible — existing inputPullCommand behavior unchanged.
Closes #776
* feat(secrets): add HashiCorp Vault as first-class premade secret source
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
* feat(lfs): add built-in elastic-git-storage support with auto-install
First-class support for elastic-git-storage as a custom LFS transfer
agent. When lfsTransferAgent is set to "elastic-git-storage" (or
"elastic-git-storage@v1.0.0" 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.
* feat(hooks): add Unity Git Hooks integration and runHookGroups
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.
* feat(orchestrator): add test workflow engine placeholder
Initial scaffold for the test workflow engine service directory.
* feat(orchestrator): add hot runner protocol placeholder
Initial scaffold for the runner registration and hot editor provider module.
* feat(orchestrator): generic artifact system — output types, manifests, and collection service
* feat(orchestrator): incremental sync protocol — git delta, direct input, and storage-backed sync
* feat: community plugin validation workflow (#800)
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
* feat(orchestrator): CI platform providers — Remote PowerShell, GitHub Actions, GitLab CI, Ansible
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.
* style: fix prettier formatting and eslint errors on test files
* feat(orchestrator): build reliability features — git integrity, reserved filename cleanup, archival
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.
* feat(reliability): implement build reliability service with git integrity, reserved filename cleanup, and build archival
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.
* test(providers): add comprehensive unit tests for GitHub Actions, GitLab CI, PowerShell, and Ansible providers (#806)
* feat(hot-runner): implement hot runner protocol with registry, health monitoring, and job dispatch (#791)
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
* feat(artifacts): complete generic artifact system with upload handlers, tests, and action integration (#798)
- 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
* feat(testing): implement test workflow engine with YAML suites, taxonomy filtering, and structured results (#790)
* feat(sync): complete incremental sync protocol with storage-pull, state management, and tests (#799)
- 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
* feat(cache): add child workspace isolation for multi-product CI builds (#777)
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.
* fix(testing): use async exec for parallel test group execution
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).
* fix(cli-provider): add timeout protection for external CLI processes
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
* fix(secrets): prevent shell injection in secret key names and mask values
- 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
* chore: rebuild dist for cli-provider timeout changes
* fix(artifacts): validate rclone availability before storage upload
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.
* fix(load-balancing): add pagination limits and rate-limit detection
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).
* fix(reliability): add disk space validation before build archival
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.
* fix(hot-runner): validate persisted registry state and add dispatcher safeguards
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.
* fix(providers): add polling timeouts, fix credential parsing, validate dependencies
- 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
* chore: rebuild dist for provider timeout and credential fixes
* fix: prettier formatting for orchestrator-folders-auth test
* ci: split orchestrator integrity into parallel jobs for faster validation
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
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* feat: add official game-ci CLI with build, activate, and orchestrate commands
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
* feat(cli): add npm publish workflow and CLI tests
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
* feat(cli): add release workflow, install scripts, and self-update command
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.
* fix(cli): address review findings — exit codes, missing inputs, null safety
- Add process.exit(1) in cli.ts catch block so failures produce non-zero exit codes
- Add 6 missing build inputs: containerRegistryRepository, containerRegistryImageVersion,
dockerIsolationMode, sshPublicKeysDirectoryPath, cacheUnityInstallationOnMac, unityHubVersionOnMac
- Add 6 missing orchestrate inputs: kubeStorageClass, readInputFromOverrideList,
readInputOverrideCommand, postBuildSteps, preBuildSteps, customJob
- Fix activate command description to accurately reflect verification behavior
- Add null check before accessing result.BuildResults in orchestrate handler
* ci: split orchestrator integrity into 4 parallel jobs to fix timeout
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.
* chore: add integration branch update scripts for release/lts-2.0.0
* ci: set macOS builds to continue-on-error
* chore: add release/lts-infrastructure to update-all script
* ci: set macOS builds to continue-on-error
* fix: make git hooks opt-in only — do not modify hooks when disabled
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.
* test: add integration wiring and input parsing tests for enterprise features
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.
* ci: mark failed macOS builds as neutral instead of failure
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.
* revert: restore build-tests-mac.yml to match main
Stop modifying the macOS build workflow — leave it identical to main.
* fix(test): add gitAuthMode to orchestrator-folders test mock
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.
* fix(ci): bump node version to 20 in integrity-check
yargs@18.0.0 requires Node >=20.19.0, so Node 18 is no longer
compatible.
* fix: downgrade yargs to ^17.7.2 and revert Node to 18 for CI compatibility
yargs@18 requires Node >=20.19.0 which is incompatible with CI's Node 18.
* refactor(cli): move cache command under orchestrate subcommand
Cache is an orchestrator feature, so it belongs under `game-ci orchestrate cache`
rather than as a top-level `game-ci cache` command.
* ci: add orchestrator compatibility validation workflow
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
* refactor: route orchestrator through plugin loader
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.
* refactor: extract orchestrator — delete 30k lines, decouple all imports
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.
* refactor: move CLI to orchestrator, fix validate-orchestrator workflow
- 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.
* fix(ci): remove reference to deleted orchestrator-integrity.yml
The orchestrator job in integrity-check.yml called the deleted
orchestrator-integrity.yml workflow, causing CI failure.
* fix(ci): use --legacy-peer-deps for orchestrator install in validation
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.
* chore: remove temporary delete-me scripts
* feat(ci): add orchestrator integration tests and plugin interface tests
- 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)
* fix(ci): add build step to k8s and aws integration jobs
The orchestrator tests need compiled output (dist/index.js) to exist
before running integration tests that spawn containers/k8s jobs.
* fix(ci): add refactor/** branch pattern and workflow_dispatch to orchestrator workflows
The refactor/orchestrator-extraction branch was not matching the
feature/** pattern, preventing the integration workflow from running
after fix commits were pushed.
* refactor(ci): split orchestrator tests into per-PR health checks and nightly exhaustive suite
validate-orchestrator.yml (per-PR, ~5 min):
- Plugin architecture health: compilation, unit tests, plugin loader
graceful degradation, installed service validation, type declaration checks
validate-orchestrator-integration.yml (daily 3 AM UTC cron, ~1-2h):
- 5 parallel jobs mirroring orchestrator-integrity.yml:
plugin-interface, k8s (5 tests), aws (10 tests),
local-docker (9 tests), rclone (1 test)
- Full LocalStack + k3d integration coverage
- continue-on-error on known flaky end2end tests
* ci: add yarn.lock to validate-orchestrator path filters
Ensure orchestrator validation runs when yarn.lock changes, since
dependency updates can affect plugin compatibility.
* refactor: move install scripts to orchestrator repo
Install scripts now live at game-ci/orchestrator where the CLI releases
are published. Removed from unity-builder to avoid duplication.
* Potential fix for code scanning alert no. 78: Workflow does not contain permissions
* refactor: rename enterprise services to plugin services
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.
* fix(ci): update workflow references from loadEnterpriseServices to loadPluginServices
CI workflows still referenced the old function name after the rename.
* ci: remove (Nightly) from integration tests workflow name
* fix: only suppress module-not-found errors in plugin loader
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.
* ci: add smoke test for orchestrator build wiring
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.
* ci: wire orchestrator integration tests into integrity check
- 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
* fix(ci): pin LocalStack to v3.8.1 for AWS SDK v3 compatibility
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.
* revert: restore localstack:latest now that SDK is pinned
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.
* ci: reorder AWS integration tests to prevent workspace corruption
Move mandatory tests (caching, locking-core, locking-get-locked) before
continue-on-error e2e tests. The e2e tests can corrupt the workspace
(delete package.json), which was causing subsequent mandatory tests to
fail with "Couldn't find a package.json".
* refactor: plugin lifecycle interface for orchestrator extraction
Replace hardcoded orchestrator params with a lifecycle-based plugin
interface. The orchestrator reads its own config from env vars —
unity-builder just calls 6 hooks (initialize, canHandleBuild,
handleBuild, beforeLocalBuild, afterLocalBuild, handlePostBuild).
Removes ~2900 lines from unity-builder (93 BuildParameters fields,
346 Input getters, 70 action.yml inputs, 400 lines of service
orchestration in index.ts).
* fix: align CI workflow with actual loadOrchestratorPlugin export
The validate-orchestrator workflows referenced loadOrchestrator and
loadPluginServices which don't exist — the source exports
loadOrchestratorPlugin. Updated all CI steps to use the correct
function name and test the actual OrchestratorPlugin lifecycle interface.
* fix: checkout matching orchestrator branch in CI validation
The validate-orchestrator workflow was always checking out the main
branch of game-ci/orchestrator. When both repos have changes on a
feature branch (e.g. refactor/orchestrator-extraction), the CI needs
to use the matching branch. Falls back to main if the branch doesn't
exist in the orchestrator repo.
* ci: add run-integration label to trigger full integration tests on PRs
PRs labeled `run-integration` now run the full orchestrator integration
suite (K8s, AWS, local-docker, rclone via LocalStack + k3d). Without the
label, integration tests only run on push to main and the daily cron.
* ci: checkout matching orchestrator branch in integration tests
Try the matching branch name (e.g. refactor/orchestrator-extraction)
from game-ci/orchestrator first, falling back to main. This allows
testing cross-repo changes before merging to orchestrator main.
* ci: switch from LocalStack to MiniStack for AWS mock services
LocalStack community edition was discontinued (2026.03.0+) and now
requires a paid license for ECS, CloudFormation, Kinesis, and other
services used in integration tests.
Switch to MiniStack (MIT, free, ministackorg/ministack) which provides
all 40+ AWS services on the same port 4566 with backward-compatible
health endpoints. ~10x smaller image, ~2s startup.
* feat: add sync-secrets workflow for sibling repositories
Manually-triggered workflow that copies secrets (Unity credentials,
AWS/GCP tokens, Codecov) from unity-builder to orchestrator or cli repos.
Supports dry-run mode. Folded from PR #825.
* Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'
* fix: add UNITY_LICENSE and NPM_TOKEN to sync-secrets, don't block on failures
* chore: remove LOCALSTACK_AUTH_TOKEN from sync-secrets workflow
MiniStack doesn't require an auth token.
---------
… (#819)
* feat(orchestrator): enterprise feature support — CLI provider, submodule profiles, caching, LFS, hooks
Add generic enterprise-grade features to the orchestrator, enabling Unity projects with
complex CI/CD pipelines to adopt game-ci/unity-builder with built-in support for:
- CLI provider protocol: JSON-over-stdin/stdout bridge enabling providers in any language
(Go, Python, Rust, shell) via the `providerExecutable` input
- Submodule profiles: YAML-based selective submodule initialization with glob patterns
and variant overlays (`submoduleProfilePath`, `submoduleVariantPath`)
- Local build caching: Filesystem-based Library and LFS caching for local builds without
external cache actions (`localCacheEnabled`, `localCacheRoot`)
- Custom LFS transfer agents: Register external transfer agents like elastic-git-storage
(`lfsTransferAgent`, `lfsTransferAgentArgs`, `lfsStoragePaths`)
- Git hooks support: Detect and install lefthook/husky with configurable skip lists
(`gitHooksEnabled`, `gitHooksSkipList`)
Also removes all `orchestrator-develop` branch references, replacing with `main`.
13 new action inputs, 13 new files, 14 new CLI provider tests, 17 submodule tests,
plus cache/LFS/hooks unit tests. All 452 tests pass.
* feat(orchestrator): add experimental GCP Cloud Run and Azure ACI providers
Add two new cloud provider implementations for the orchestrator, both marked
as experimental:
- **GCP Cloud Run Jobs** (`providerStrategy: gcp-cloud-run`): Executes Unity
builds as Cloud Run Jobs with GCS FUSE for large artifact storage. Supports
configurable machine types, service accounts, and VPC connectors. 7 new inputs
(gcpProject, gcpRegion, gcpBucket, gcpMachineType, gcpDiskSizeGb,
gcpServiceAccount, gcpVpcConnector).
- **Azure Container Instances** (`providerStrategy: azure-aci`): Executes Unity
builds as ACI containers with Azure File Shares (Premium FileStorage) for
large artifact storage up to 100 TiB. Supports configurable CPU/memory,
VNet integration, and subscription targeting. 9 new inputs
(azureResourceGroup, azureLocation, azureStorageAccount, azureFileShareName,
azureSubscriptionId, azureCpu, azureMemoryGb, azureDiskSizeGb, azureSubnetId).
Both providers use their respective CLIs (gcloud, az) for infrastructure
management and support garbage collection of old build resources. No tests
included as these require real cloud infrastructure to validate.
* feat(orchestrator): multi-storage support for GCP and Azure providers
Both providers now support four storage backends via gcpStorageType / azureStorageType:
GCP Cloud Run:
- gcs-fuse: Mount GCS bucket as POSIX filesystem (unlimited, best for large sequential I/O)
- gcs-copy: Copy artifacts in/out via gsutil (simpler, no FUSE overhead)
- nfs: Filestore NFS mount (true POSIX, good random I/O, up to 100 TiB)
- in-memory: tmpfs (fastest, volatile, up to 32 GiB)
Azure ACI:
- azure-files: SMB file share mount (up to 100 TiB, premium throughput)
- blob-copy: Copy artifacts in/out via az storage blob (no mount overhead)
- azure-files-nfs: NFS 4.1 file share mount (true POSIX, no SMB lock overhead)
- in-memory: emptyDir tmpfs (fastest, volatile, limited by container memory)
New inputs: gcpStorageType, gcpFilestoreIp, gcpFilestoreShare, azureStorageType,
azureBlobContainer. Constructor validates storage config and warns on missing
prerequisites (e.g. NFS requires VPC connector/subnet).
* feat(orchestrator): automatic provider fallback with runner availability check
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.
* feat(orchestrator): add retry-on-fallback and provider init timeout
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.
* style: format changed files with prettier
* test(orchestrator): expand local cache service test coverage
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.
* test(orchestrator): add runner availability service tests
Covers: no token skip, no runners fallback, busy/offline runners,
label filtering (case-insensitive), minAvailable threshold,
fail-open on API error, mixed runner states.
* test(orchestrator): add unit tests for untested core services
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).
* ci(orchestrator): add fast unit test gate to integrity workflow
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.
* test(orchestrator): expand unit tests for enterprise services
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.
* fix(orchestrator): use http.extraHeader for secure git authentication
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
* feat(orchestrator): add premade secret sources and YAML definitions
Add SecretSourceService with premade secret source integrations:
- aws-secrets-manager (with --query SecretString for direct value)
- aws-parameter-store (with --with-decryption)
- gcp-secret-manager (latest version)
- azure-key-vault (via $AZURE_VAULT_NAME env var)
- env (environment variables, no shell command needed)
- Custom commands (any string with {0} placeholder)
- YAML file definitions for custom sources
Add secretSource input that takes precedence over inputPullCommand.
Backward compatible — existing inputPullCommand behavior unchanged.
Closes #776
* feat(secrets): add HashiCorp Vault as first-class premade secret source
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
* feat(lfs): add built-in elastic-git-storage support with auto-install
First-class support for elastic-git-storage as a custom LFS transfer
agent. When lfsTransferAgent is set to "elastic-git-storage" (or
"elastic-git-storage@v1.0.0" 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.
* feat(hooks): add Unity Git Hooks integration and runHookGroups
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.
* feat(orchestrator): add test workflow engine placeholder
Initial scaffold for the test workflow engine service directory.
* feat(orchestrator): add hot runner protocol placeholder
Initial scaffold for the runner registration and hot editor provider module.
* feat(orchestrator): generic artifact system — output types, manifests, and collection service
* feat(orchestrator): incremental sync protocol — git delta, direct input, and storage-backed sync
* feat: community plugin validation workflow (#800)
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
* feat(orchestrator): CI platform providers — Remote PowerShell, GitHub Actions, GitLab CI, Ansible
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.
* style: fix prettier formatting and eslint errors on test files
* feat(orchestrator): build reliability features — git integrity, reserved filename cleanup, archival
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.
* feat(reliability): implement build reliability service with git integrity, reserved filename cleanup, and build archival
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.
* test(providers): add comprehensive unit tests for GitHub Actions, GitLab CI, PowerShell, and Ansible providers (#806)
* feat(hot-runner): implement hot runner protocol with registry, health monitoring, and job dispatch (#791)
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
* feat(artifacts): complete generic artifact system with upload handlers, tests, and action integration (#798)
- 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
* feat(testing): implement test workflow engine with YAML suites, taxonomy filtering, and structured results (#790)
* feat(sync): complete incremental sync protocol with storage-pull, state management, and tests (#799)
- 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
* feat(cache): add child workspace isolation for multi-product CI builds (#777)
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.
* fix(testing): use async exec for parallel test group execution
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).
* fix(cli-provider): add timeout protection for external CLI processes
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
* fix(secrets): prevent shell injection in secret key names and mask values
- 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
* chore: rebuild dist for cli-provider timeout changes
* fix(artifacts): validate rclone availability before storage upload
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.
* fix(load-balancing): add pagination limits and rate-limit detection
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).
* fix(reliability): add disk space validation before build archival
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.
* fix(hot-runner): validate persisted registry state and add dispatcher safeguards
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.
* fix(providers): add polling timeouts, fix credential parsing, validate dependencies
- 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
* chore: rebuild dist for provider timeout and credential fixes
* fix: prettier formatting for orchestrator-folders-auth test
* ci: split orchestrator integrity into parallel jobs for faster validation
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
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* feat: add official game-ci CLI with build, activate, and orchestrate commands
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
* feat(cli): add npm publish workflow and CLI tests
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
* feat(cli): add release workflow, install scripts, and self-update command
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.
* fix(cli): address review findings — exit codes, missing inputs, null safety
- Add process.exit(1) in cli.ts catch block so failures produce non-zero exit codes
- Add 6 missing build inputs: containerRegistryRepository, containerRegistryImageVersion,
dockerIsolationMode, sshPublicKeysDirectoryPath, cacheUnityInstallationOnMac, unityHubVersionOnMac
- Add 6 missing orchestrate inputs: kubeStorageClass, readInputFromOverrideList,
readInputOverrideCommand, postBuildSteps, preBuildSteps, customJob
- Fix activate command description to accurately reflect verification behavior
- Add null check before accessing result.BuildResults in orchestrate handler
* ci: split orchestrator integrity into 4 parallel jobs to fix timeout
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.
* chore: add integration branch update scripts for release/lts-2.0.0
* ci: set macOS builds to continue-on-error
* chore: add release/lts-infrastructure to update-all script
* ci: set macOS builds to continue-on-error
* fix: make git hooks opt-in only — do not modify hooks when disabled
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.
* test: add integration wiring and input parsing tests for enterprise features
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.
* ci: mark failed macOS builds as neutral instead of failure
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.
* revert: restore build-tests-mac.yml to match main
Stop modifying the macOS build workflow — leave it identical to main.
* fix(test): add gitAuthMode to orchestrator-folders test mock
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.
* fix(ci): bump node version to 20 in integrity-check
yargs@18.0.0 requires Node >=20.19.0, so Node 18 is no longer
compatible.
* fix: downgrade yargs to ^17.7.2 and revert Node to 18 for CI compatibility
yargs@18 requires Node >=20.19.0 which is incompatible with CI's Node 18.
* refactor(cli): move cache command under orchestrate subcommand
Cache is an orchestrator feature, so it belongs under `game-ci orchestrate cache`
rather than as a top-level `game-ci cache` command.
* ci: add orchestrator compatibility validation workflow
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
* refactor: route orchestrator through plugin loader
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.
* refactor: extract orchestrator — delete 30k lines, decouple all imports
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.
* refactor: move CLI to orchestrator, fix validate-orchestrator workflow
- 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.
* fix(ci): remove reference to deleted orchestrator-integrity.yml
The orchestrator job in integrity-check.yml called the deleted
orchestrator-integrity.yml workflow, causing CI failure.
* fix(ci): use --legacy-peer-deps for orchestrator install in validation
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.
* chore: remove temporary delete-me scripts
* feat(ci): add orchestrator integration tests and plugin interface tests
- 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)
* fix(ci): add build step to k8s and aws integration jobs
The orchestrator tests need compiled output (dist/index.js) to exist
before running integration tests that spawn containers/k8s jobs.
* fix(ci): add refactor/** branch pattern and workflow_dispatch to orchestrator workflows
The refactor/orchestrator-extraction branch was not matching the
feature/** pattern, preventing the integration workflow from running
after fix commits were pushed.
* refactor(ci): split orchestrator tests into per-PR health checks and nightly exhaustive suite
validate-orchestrator.yml (per-PR, ~5 min):
- Plugin architecture health: compilation, unit tests, plugin loader
graceful degradation, installed service validation, type declaration checks
validate-orchestrator-integration.yml (daily 3 AM UTC cron, ~1-2h):
- 5 parallel jobs mirroring orchestrator-integrity.yml:
plugin-interface, k8s (5 tests), aws (10 tests),
local-docker (9 tests), rclone (1 test)
- Full LocalStack + k3d integration coverage
- continue-on-error on known flaky end2end tests
* ci: add yarn.lock to validate-orchestrator path filters
Ensure orchestrator validation runs when yarn.lock changes, since
dependency updates can affect plugin compatibility.
* refactor: move install scripts to orchestrator repo
Install scripts now live at game-ci/orchestrator where the CLI releases
are published. Removed from unity-builder to avoid duplication.
* Potential fix for code scanning alert no. 78: Workflow does not contain permissions
* refactor: rename enterprise services to plugin services
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.
* fix(ci): update workflow references from loadEnterpriseServices to loadPluginServices
CI workflows still referenced the old function name after the rename.
* ci: remove (Nightly) from integration tests workflow name
* fix: only suppress module-not-found errors in plugin loader
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.
* ci: add smoke test for orchestrator build wiring
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.
* ci: wire orchestrator integration tests into integrity check
- 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
* fix(ci): pin LocalStack to v3.8.1 for AWS SDK v3 compatibility
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.
* revert: restore localstack:latest now that SDK is pinned
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.
* ci: reorder AWS integration tests to prevent workspace corruption
Move mandatory tests (caching, locking-core, locking-get-locked) before
continue-on-error e2e tests. The e2e tests can corrupt the workspace
(delete package.json), which was causing subsequent mandatory tests to
fail with "Couldn't find a package.json".
* refactor: plugin lifecycle interface for orchestrator extraction
Replace hardcoded orchestrator params with a lifecycle-based plugin
interface. The orchestrator reads its own config from env vars —
unity-builder just calls 6 hooks (initialize, canHandleBuild,
handleBuild, beforeLocalBuild, afterLocalBuild, handlePostBuild).
Removes ~2900 lines from unity-builder (93 BuildParameters fields,
346 Input getters, 70 action.yml inputs, 400 lines of service
orchestration in index.ts).
* fix: align CI workflow with actual loadOrchestratorPlugin export
The validate-orchestrator workflows referenced loadOrchestrator and
loadPluginServices which don't exist — the source exports
loadOrchestratorPlugin. Updated all CI steps to use the correct
function name and test the actual OrchestratorPlugin lifecycle interface.
* fix: checkout matching orchestrator branch in CI validation
The validate-orchestrator workflow was always checking out the main
branch of game-ci/orchestrator. When both repos have changes on a
feature branch (e.g. refactor/orchestrator-extraction), the CI needs
to use the matching branch. Falls back to main if the branch doesn't
exist in the orchestrator repo.
* ci: add run-integration label to trigger full integration tests on PRs
PRs labeled `run-integration` now run the full orchestrator integration
suite (K8s, AWS, local-docker, rclone via LocalStack + k3d). Without the
label, integration tests only run on push to main and the daily cron.
* ci: checkout matching orchestrator branch in integration tests
Try the matching branch name (e.g. refactor/orchestrator-extraction)
from game-ci/orchestrator first, falling back to main. This allows
testing cross-repo changes before merging to orchestrator main.
* ci: switch from LocalStack to MiniStack for AWS mock services
LocalStack community edition was discontinued (2026.03.0+) and now
requires a paid license for ECS, CloudFormation, Kinesis, and other
services used in integration tests.
Switch to MiniStack (MIT, free, ministackorg/ministack) which provides
all 40+ AWS services on the same port 4566 with backward-compatible
health endpoints. ~10x smaller image, ~2s startup.
* feat: add sync-secrets workflow for sibling repositories
Manually-triggered workflow that copies secrets (Unity credentials,
AWS/GCP tokens, Codecov) from unity-builder to orchestrator or cli repos.
Supports dry-run mode. Folded from PR #825.
* Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'
* fix: add UNITY_LICENSE and NPM_TOKEN to sync-secrets, don't block on failures
* chore: remove LOCALSTACK_AUTH_TOKEN from sync-secrets workflow
MiniStack doesn't require an auth token.
---------
… (#819)
* feat(orchestrator): enterprise feature support — CLI provider, submodule profiles, caching, LFS, hooks
Add generic enterprise-grade features to the orchestrator, enabling Unity projects with
complex CI/CD pipelines to adopt game-ci/unity-builder with built-in support for:
- CLI provider protocol: JSON-over-stdin/stdout bridge enabling providers in any language
(Go, Python, Rust, shell) via the `providerExecutable` input
- Submodule profiles: YAML-based selective submodule initialization with glob patterns
and variant overlays (`submoduleProfilePath`, `submoduleVariantPath`)
- Local build caching: Filesystem-based Library and LFS caching for local builds without
external cache actions (`localCacheEnabled`, `localCacheRoot`)
- Custom LFS transfer agents: Register external transfer agents like elastic-git-storage
(`lfsTransferAgent`, `lfsTransferAgentArgs`, `lfsStoragePaths`)
- Git hooks support: Detect and install lefthook/husky with configurable skip lists
(`gitHooksEnabled`, `gitHooksSkipList`)
Also removes all `orchestrator-develop` branch references, replacing with `main`.
13 new action inputs, 13 new files, 14 new CLI provider tests, 17 submodule tests,
plus cache/LFS/hooks unit tests. All 452 tests pass.
* feat(orchestrator): add experimental GCP Cloud Run and Azure ACI providers
Add two new cloud provider implementations for the orchestrator, both marked
as experimental:
- **GCP Cloud Run Jobs** (`providerStrategy: gcp-cloud-run`): Executes Unity
builds as Cloud Run Jobs with GCS FUSE for large artifact storage. Supports
configurable machine types, service accounts, and VPC connectors. 7 new inputs
(gcpProject, gcpRegion, gcpBucket, gcpMachineType, gcpDiskSizeGb,
gcpServiceAccount, gcpVpcConnector).
- **Azure Container Instances** (`providerStrategy: azure-aci`): Executes Unity
builds as ACI containers with Azure File Shares (Premium FileStorage) for
large artifact storage up to 100 TiB. Supports configurable CPU/memory,
VNet integration, and subscription targeting. 9 new inputs
(azureResourceGroup, azureLocation, azureStorageAccount, azureFileShareName,
azureSubscriptionId, azureCpu, azureMemoryGb, azureDiskSizeGb, azureSubnetId).
Both providers use their respective CLIs (gcloud, az) for infrastructure
management and support garbage collection of old build resources. No tests
included as these require real cloud infrastructure to validate.
* feat(orchestrator): multi-storage support for GCP and Azure providers
Both providers now support four storage backends via gcpStorageType / azureStorageType:
GCP Cloud Run:
- gcs-fuse: Mount GCS bucket as POSIX filesystem (unlimited, best for large sequential I/O)
- gcs-copy: Copy artifacts in/out via gsutil (simpler, no FUSE overhead)
- nfs: Filestore NFS mount (true POSIX, good random I/O, up to 100 TiB)
- in-memory: tmpfs (fastest, volatile, up to 32 GiB)
Azure ACI:
- azure-files: SMB file share mount (up to 100 TiB, premium throughput)
- blob-copy: Copy artifacts in/out via az storage blob (no mount overhead)
- azure-files-nfs: NFS 4.1 file share mount (true POSIX, no SMB lock overhead)
- in-memory: emptyDir tmpfs (fastest, volatile, limited by container memory)
New inputs: gcpStorageType, gcpFilestoreIp, gcpFilestoreShare, azureStorageType,
azureBlobContainer. Constructor validates storage config and warns on missing
prerequisites (e.g. NFS requires VPC connector/subnet).
* feat(orchestrator): automatic provider fallback with runner availability check
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.
* feat(orchestrator): add retry-on-fallback and provider init timeout
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.
* style: format changed files with prettier
* test(orchestrator): expand local cache service test coverage
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.
* test(orchestrator): add runner availability service tests
Covers: no token skip, no runners fallback, busy/offline runners,
label filtering (case-insensitive), minAvailable threshold,
fail-open on API error, mixed runner states.
* test(orchestrator): add unit tests for untested core services
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).
* ci(orchestrator): add fast unit test gate to integrity workflow
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.
* test(orchestrator): expand unit tests for enterprise services
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.
* fix(orchestrator): use http.extraHeader for secure git authentication
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
* feat(orchestrator): add premade secret sources and YAML definitions
Add SecretSourceService with premade secret source integrations:
- aws-secrets-manager (with --query SecretString for direct value)
- aws-parameter-store (with --with-decryption)
- gcp-secret-manager (latest version)
- azure-key-vault (via $AZURE_VAULT_NAME env var)
- env (environment variables, no shell command needed)
- Custom commands (any string with {0} placeholder)
- YAML file definitions for custom sources
Add secretSource input that takes precedence over inputPullCommand.
Backward compatible — existing inputPullCommand behavior unchanged.
Closes #776
* feat(secrets): add HashiCorp Vault as first-class premade secret source
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
* feat(lfs): add built-in elastic-git-storage support with auto-install
First-class support for elastic-git-storage as a custom LFS transfer
agent. When lfsTransferAgent is set to "elastic-git-storage" (or
"elastic-git-storage@v1.0.0" 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.
* feat(hooks): add Unity Git Hooks integration and runHookGroups
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.
* feat(orchestrator): add test workflow engine placeholder
Initial scaffold for the test workflow engine service directory.
* feat(orchestrator): add hot runner protocol placeholder
Initial scaffold for the runner registration and hot editor provider module.
* feat(orchestrator): generic artifact system — output types, manifests, and collection service
* feat(orchestrator): incremental sync protocol — git delta, direct input, and storage-backed sync
* feat: community plugin validation workflow (#800)
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
* feat(orchestrator): CI platform providers — Remote PowerShell, GitHub Actions, GitLab CI, Ansible
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.
* style: fix prettier formatting and eslint errors on test files
* feat(orchestrator): build reliability features — git integrity, reserved filename cleanup, archival
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.
* feat(reliability): implement build reliability service with git integrity, reserved filename cleanup, and build archival
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.
* test(providers): add comprehensive unit tests for GitHub Actions, GitLab CI, PowerShell, and Ansible providers (#806)
* feat(hot-runner): implement hot runner protocol with registry, health monitoring, and job dispatch (#791)
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
* feat(artifacts): complete generic artifact system with upload handlers, tests, and action integration (#798)
- 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
* feat(testing): implement test workflow engine with YAML suites, taxonomy filtering, and structured results (#790)
* feat(sync): complete incremental sync protocol with storage-pull, state management, and tests (#799)
- 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
* feat(cache): add child workspace isolation for multi-product CI builds (#777)
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.
* fix(testing): use async exec for parallel test group execution
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).
* fix(cli-provider): add timeout protection for external CLI processes
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
* fix(secrets): prevent shell injection in secret key names and mask values
- 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
* chore: rebuild dist for cli-provider timeout changes
* fix(artifacts): validate rclone availability before storage upload
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.
* fix(load-balancing): add pagination limits and rate-limit detection
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).
* fix(reliability): add disk space validation before build archival
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.
* fix(hot-runner): validate persisted registry state and add dispatcher safeguards
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.
* fix(providers): add polling timeouts, fix credential parsing, validate dependencies
- 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
* chore: rebuild dist for provider timeout and credential fixes
* fix: prettier formatting for orchestrator-folders-auth test
* ci: split orchestrator integrity into parallel jobs for faster validation
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
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* feat: add official game-ci CLI with build, activate, and orchestrate commands
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
* feat(cli): add npm publish workflow and CLI tests
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
* feat(cli): add release workflow, install scripts, and self-update command
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.
* fix(cli): address review findings — exit codes, missing inputs, null safety
- Add process.exit(1) in cli.ts catch block so failures produce non-zero exit codes
- Add 6 missing build inputs: containerRegistryRepository, containerRegistryImageVersion,
dockerIsolationMode, sshPublicKeysDirectoryPath, cacheUnityInstallationOnMac, unityHubVersionOnMac
- Add 6 missing orchestrate inputs: kubeStorageClass, readInputFromOverrideList,
readInputOverrideCommand, postBuildSteps, preBuildSteps, customJob
- Fix activate command description to accurately reflect verification behavior
- Add null check before accessing result.BuildResults in orchestrate handler
* ci: split orchestrator integrity into 4 parallel jobs to fix timeout
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.
* chore: add integration branch update scripts for release/lts-2.0.0
* ci: set macOS builds to continue-on-error
* chore: add release/lts-infrastructure to update-all script
* ci: set macOS builds to continue-on-error
* fix: make git hooks opt-in only — do not modify hooks when disabled
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.
* test: add integration wiring and input parsing tests for enterprise features
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.
* ci: mark failed macOS builds as neutral instead of failure
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.
* revert: restore build-tests-mac.yml to match main
Stop modifying the macOS build workflow — leave it identical to main.
* fix(test): add gitAuthMode to orchestrator-folders test mock
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.
* fix(ci): bump node version to 20 in integrity-check
yargs@18.0.0 requires Node >=20.19.0, so Node 18 is no longer
compatible.
* fix: downgrade yargs to ^17.7.2 and revert Node to 18 for CI compatibility
yargs@18 requires Node >=20.19.0 which is incompatible with CI's Node 18.
* refactor(cli): move cache command under orchestrate subcommand
Cache is an orchestrator feature, so it belongs under `game-ci orchestrate cache`
rather than as a top-level `game-ci cache` command.
* ci: add orchestrator compatibility validation workflow
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
* refactor: route orchestrator through plugin loader
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.
* refactor: extract orchestrator — delete 30k lines, decouple all imports
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.
* refactor: move CLI to orchestrator, fix validate-orchestrator workflow
- 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.
* fix(ci): remove reference to deleted orchestrator-integrity.yml
The orchestrator job in integrity-check.yml called the deleted
orchestrator-integrity.yml workflow, causing CI failure.
* fix(ci): use --legacy-peer-deps for orchestrator install in validation
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.
* chore: remove temporary delete-me scripts
* feat(ci): add orchestrator integration tests and plugin interface tests
- 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)
* fix(ci): add build step to k8s and aws integration jobs
The orchestrator tests need compiled output (dist/index.js) to exist
before running integration tests that spawn containers/k8s jobs.
* fix(ci): add refactor/** branch pattern and workflow_dispatch to orchestrator workflows
The refactor/orchestrator-extraction branch was not matching the
feature/** pattern, preventing the integration workflow from running
after fix commits were pushed.
* refactor(ci): split orchestrator tests into per-PR health checks and nightly exhaustive suite
validate-orchestrator.yml (per-PR, ~5 min):
- Plugin architecture health: compilation, unit tests, plugin loader
graceful degradation, installed service validation, type declaration checks
validate-orchestrator-integration.yml (daily 3 AM UTC cron, ~1-2h):
- 5 parallel jobs mirroring orchestrator-integrity.yml:
plugin-interface, k8s (5 tests), aws (10 tests),
local-docker (9 tests), rclone (1 test)
- Full LocalStack + k3d integration coverage
- continue-on-error on known flaky end2end tests
* ci: add yarn.lock to validate-orchestrator path filters
Ensure orchestrator validation runs when yarn.lock changes, since
dependency updates can affect plugin compatibility.
* refactor: move install scripts to orchestrator repo
Install scripts now live at game-ci/orchestrator where the CLI releases
are published. Removed from unity-builder to avoid duplication.
* Potential fix for code scanning alert no. 78: Workflow does not contain permissions
* refactor: rename enterprise services to plugin services
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.
* fix(ci): update workflow references from loadEnterpriseServices to loadPluginServices
CI workflows still referenced the old function name after the rename.
* ci: remove (Nightly) from integration tests workflow name
* fix: only suppress module-not-found errors in plugin loader
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.
* ci: add smoke test for orchestrator build wiring
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.
* ci: wire orchestrator integration tests into integrity check
- 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
* fix(ci): pin LocalStack to v3.8.1 for AWS SDK v3 compatibility
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.
* revert: restore localstack:latest now that SDK is pinned
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.
* ci: reorder AWS integration tests to prevent workspace corruption
Move mandatory tests (caching, locking-core, locking-get-locked) before
continue-on-error e2e tests. The e2e tests can corrupt the workspace
(delete package.json), which was causing subsequent mandatory tests to
fail with "Couldn't find a package.json".
* refactor: plugin lifecycle interface for orchestrator extraction
Replace hardcoded orchestrator params with a lifecycle-based plugin
interface. The orchestrator reads its own config from env vars —
unity-builder just calls 6 hooks (initialize, canHandleBuild,
handleBuild, beforeLocalBuild, afterLocalBuild, handlePostBuild).
Removes ~2900 lines from unity-builder (93 BuildParameters fields,
346 Input getters, 70 action.yml inputs, 400 lines of service
orchestration in index.ts).
* fix: align CI workflow with actual loadOrchestratorPlugin export
The validate-orchestrator workflows referenced loadOrchestrator and
loadPluginServices which don't exist — the source exports
loadOrchestratorPlugin. Updated all CI steps to use the correct
function name and test the actual OrchestratorPlugin lifecycle interface.
* fix: checkout matching orchestrator branch in CI validation
The validate-orchestrator workflow was always checking out the main
branch of game-ci/orchestrator. When both repos have changes on a
feature branch (e.g. refactor/orchestrator-extraction), the CI needs
to use the matching branch. Falls back to main if the branch doesn't
exist in the orchestrator repo.
* ci: add run-integration label to trigger full integration tests on PRs
PRs labeled `run-integration` now run the full orchestrator integration
suite (K8s, AWS, local-docker, rclone via LocalStack + k3d). Without the
label, integration tests only run on push to main and the daily cron.
* ci: checkout matching orchestrator branch in integration tests
Try the matching branch name (e.g. refactor/orchestrator-extraction)
from game-ci/orchestrator first, falling back to main. This allows
testing cross-repo changes before merging to orchestrator main.
* ci: switch from LocalStack to MiniStack for AWS mock services
LocalStack community edition was discontinued (2026.03.0+) and now
requires a paid license for ECS, CloudFormation, Kinesis, and other
services used in integration tests.
Switch to MiniStack (MIT, free, ministackorg/ministack) which provides
all 40+ AWS services on the same port 4566 with backward-compatible
health endpoints. ~10x smaller image, ~2s startup.
* feat: add sync-secrets workflow for sibling repositories
Manually-triggered workflow that copies secrets (Unity credentials,
AWS/GCP tokens, Codecov) from unity-builder to orchestrator or cli repos.
Supports dry-run mode. Folded from PR #825.
* Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'
* fix: add UNITY_LICENSE and NPM_TOKEN to sync-secrets, don't block on failures
* chore: remove LOCALSTACK_AUTH_TOKEN from sync-secrets workflow
MiniStack doesn't require an auth token.
---------
… (#819)
* feat(orchestrator): enterprise feature support — CLI provider, submodule profiles, caching, LFS, hooks
Add generic enterprise-grade features to the orchestrator, enabling Unity projects with
complex CI/CD pipelines to adopt game-ci/unity-builder with built-in support for:
- CLI provider protocol: JSON-over-stdin/stdout bridge enabling providers in any language
(Go, Python, Rust, shell) via the `providerExecutable` input
- Submodule profiles: YAML-based selective submodule initialization with glob patterns
and variant overlays (`submoduleProfilePath`, `submoduleVariantPath`)
- Local build caching: Filesystem-based Library and LFS caching for local builds without
external cache actions (`localCacheEnabled`, `localCacheRoot`)
- Custom LFS transfer agents: Register external transfer agents like elastic-git-storage
(`lfsTransferAgent`, `lfsTransferAgentArgs`, `lfsStoragePaths`)
- Git hooks support: Detect and install lefthook/husky with configurable skip lists
(`gitHooksEnabled`, `gitHooksSkipList`)
Also removes all `orchestrator-develop` branch references, replacing with `main`.
13 new action inputs, 13 new files, 14 new CLI provider tests, 17 submodule tests,
plus cache/LFS/hooks unit tests. All 452 tests pass.
* feat(orchestrator): add experimental GCP Cloud Run and Azure ACI providers
Add two new cloud provider implementations for the orchestrator, both marked
as experimental:
- **GCP Cloud Run Jobs** (`providerStrategy: gcp-cloud-run`): Executes Unity
builds as Cloud Run Jobs with GCS FUSE for large artifact storage. Supports
configurable machine types, service accounts, and VPC connectors. 7 new inputs
(gcpProject, gcpRegion, gcpBucket, gcpMachineType, gcpDiskSizeGb,
gcpServiceAccount, gcpVpcConnector).
- **Azure Container Instances** (`providerStrategy: azure-aci`): Executes Unity
builds as ACI containers with Azure File Shares (Premium FileStorage) for
large artifact storage up to 100 TiB. Supports configurable CPU/memory,
VNet integration, and subscription targeting. 9 new inputs
(azureResourceGroup, azureLocation, azureStorageAccount, azureFileShareName,
azureSubscriptionId, azureCpu, azureMemoryGb, azureDiskSizeGb, azureSubnetId).
Both providers use their respective CLIs (gcloud, az) for infrastructure
management and support garbage collection of old build resources. No tests
included as these require real cloud infrastructure to validate.
* feat(orchestrator): multi-storage support for GCP and Azure providers
Both providers now support four storage backends via gcpStorageType / azureStorageType:
GCP Cloud Run:
- gcs-fuse: Mount GCS bucket as POSIX filesystem (unlimited, best for large sequential I/O)
- gcs-copy: Copy artifacts in/out via gsutil (simpler, no FUSE overhead)
- nfs: Filestore NFS mount (true POSIX, good random I/O, up to 100 TiB)
- in-memory: tmpfs (fastest, volatile, up to 32 GiB)
Azure ACI:
- azure-files: SMB file share mount (up to 100 TiB, premium throughput)
- blob-copy: Copy artifacts in/out via az storage blob (no mount overhead)
- azure-files-nfs: NFS 4.1 file share mount (true POSIX, no SMB lock overhead)
- in-memory: emptyDir tmpfs (fastest, volatile, limited by container memory)
New inputs: gcpStorageType, gcpFilestoreIp, gcpFilestoreShare, azureStorageType,
azureBlobContainer. Constructor validates storage config and warns on missing
prerequisites (e.g. NFS requires VPC connector/subnet).
* feat(orchestrator): automatic provider fallback with runner availability check
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.
* feat(orchestrator): add retry-on-fallback and provider init timeout
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.
* style: format changed files with prettier
* test(orchestrator): expand local cache service test coverage
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.
* test(orchestrator): add runner availability service tests
Covers: no token skip, no runners fallback, busy/offline runners,
label filtering (case-insensitive), minAvailable threshold,
fail-open on API error, mixed runner states.
* test(orchestrator): add unit tests for untested core services
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).
* ci(orchestrator): add fast unit test gate to integrity workflow
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.
* test(orchestrator): expand unit tests for enterprise services
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.
* fix(orchestrator): use http.extraHeader for secure git authentication
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
* feat(orchestrator): add premade secret sources and YAML definitions
Add SecretSourceService with premade secret source integrations:
- aws-secrets-manager (with --query SecretString for direct value)
- aws-parameter-store (with --with-decryption)
- gcp-secret-manager (latest version)
- azure-key-vault (via $AZURE_VAULT_NAME env var)
- env (environment variables, no shell command needed)
- Custom commands (any string with {0} placeholder)
- YAML file definitions for custom sources
Add secretSource input that takes precedence over inputPullCommand.
Backward compatible — existing inputPullCommand behavior unchanged.
Closes #776
* feat(secrets): add HashiCorp Vault as first-class premade secret source
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
* feat(lfs): add built-in elastic-git-storage support with auto-install
First-class support for elastic-git-storage as a custom LFS transfer
agent. When lfsTransferAgent is set to "elastic-git-storage" (or
"elastic-git-storage@v1.0.0" 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.
* feat(hooks): add Unity Git Hooks integration and runHookGroups
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.
* feat(orchestrator): add test workflow engine placeholder
Initial scaffold for the test workflow engine service directory.
* feat(orchestrator): add hot runner protocol placeholder
Initial scaffold for the runner registration and hot editor provider module.
* feat(orchestrator): generic artifact system — output types, manifests, and collection service
* feat(orchestrator): incremental sync protocol — git delta, direct input, and storage-backed sync
* feat: community plugin validation workflow (#800)
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
* feat(orchestrator): CI platform providers — Remote PowerShell, GitHub Actions, GitLab CI, Ansible
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.
* style: fix prettier formatting and eslint errors on test files
* feat(orchestrator): build reliability features — git integrity, reserved filename cleanup, archival
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.
* feat(reliability): implement build reliability service with git integrity, reserved filename cleanup, and build archival
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.
* test(providers): add comprehensive unit tests for GitHub Actions, GitLab CI, PowerShell, and Ansible providers (#806)
* feat(hot-runner): implement hot runner protocol with registry, health monitoring, and job dispatch (#791)
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
* feat(artifacts): complete generic artifact system with upload handlers, tests, and action integration (#798)
- 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
* feat(testing): implement test workflow engine with YAML suites, taxonomy filtering, and structured results (#790)
* feat(sync): complete incremental sync protocol with storage-pull, state management, and tests (#799)
- 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
* feat(cache): add child workspace isolation for multi-product CI builds (#777)
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.
* fix(testing): use async exec for parallel test group execution
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).
* fix(cli-provider): add timeout protection for external CLI processes
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
* fix(secrets): prevent shell injection in secret key names and mask values
- 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
* chore: rebuild dist for cli-provider timeout changes
* fix(artifacts): validate rclone availability before storage upload
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.
* fix(load-balancing): add pagination limits and rate-limit detection
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).
* fix(reliability): add disk space validation before build archival
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.
* fix(hot-runner): validate persisted registry state and add dispatcher safeguards
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.
* fix(providers): add polling timeouts, fix credential parsing, validate dependencies
- 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
* chore: rebuild dist for provider timeout and credential fixes
* fix: prettier formatting for orchestrator-folders-auth test
* ci: split orchestrator integrity into parallel jobs for faster validation
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
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* feat: add official game-ci CLI with build, activate, and orchestrate commands
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
* feat(cli): add npm publish workflow and CLI tests
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
* feat(cli): add release workflow, install scripts, and self-update command
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.
* fix(cli): address review findings — exit codes, missing inputs, null safety
- Add process.exit(1) in cli.ts catch block so failures produce non-zero exit codes
- Add 6 missing build inputs: containerRegistryRepository, containerRegistryImageVersion,
dockerIsolationMode, sshPublicKeysDirectoryPath, cacheUnityInstallationOnMac, unityHubVersionOnMac
- Add 6 missing orchestrate inputs: kubeStorageClass, readInputFromOverrideList,
readInputOverrideCommand, postBuildSteps, preBuildSteps, customJob
- Fix activate command description to accurately reflect verification behavior
- Add null check before accessing result.BuildResults in orchestrate handler
* ci: split orchestrator integrity into 4 parallel jobs to fix timeout
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.
* chore: add integration branch update scripts for release/lts-2.0.0
* ci: set macOS builds to continue-on-error
* chore: add release/lts-infrastructure to update-all script
* ci: set macOS builds to continue-on-error
* fix: make git hooks opt-in only — do not modify hooks when disabled
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.
* test: add integration wiring and input parsing tests for enterprise features
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.
* ci: mark failed macOS builds as neutral instead of failure
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.
* revert: restore build-tests-mac.yml to match main
Stop modifying the macOS build workflow — leave it identical to main.
* fix(test): add gitAuthMode to orchestrator-folders test mock
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.
* fix(ci): bump node version to 20 in integrity-check
yargs@18.0.0 requires Node >=20.19.0, so Node 18 is no longer
compatible.
* fix: downgrade yargs to ^17.7.2 and revert Node to 18 for CI compatibility
yargs@18 requires Node >=20.19.0 which is incompatible with CI's Node 18.
* refactor(cli): move cache command under orchestrate subcommand
Cache is an orchestrator feature, so it belongs under `game-ci orchestrate cache`
rather than as a top-level `game-ci cache` command.
* ci: add orchestrator compatibility validation workflow
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
* refactor: route orchestrator through plugin loader
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.
* refactor: extract orchestrator — delete 30k lines, decouple all imports
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.
* refactor: move CLI to orchestrator, fix validate-orchestrator workflow
- 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.
* fix(ci): remove reference to deleted orchestrator-integrity.yml
The orchestrator job in integrity-check.yml called the deleted
orchestrator-integrity.yml workflow, causing CI failure.
* fix(ci): use --legacy-peer-deps for orchestrator install in validation
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.
* chore: remove temporary delete-me scripts
* feat(ci): add orchestrator integration tests and plugin interface tests
- 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)
* fix(ci): add build step to k8s and aws integration jobs
The orchestrator tests need compiled output (dist/index.js) to exist
before running integration tests that spawn containers/k8s jobs.
* fix(ci): add refactor/** branch pattern and workflow_dispatch to orchestrator workflows
The refactor/orchestrator-extraction branch was not matching the
feature/** pattern, preventing the integration workflow from running
after fix commits were pushed.
* refactor(ci): split orchestrator tests into per-PR health checks and nightly exhaustive suite
validate-orchestrator.yml (per-PR, ~5 min):
- Plugin architecture health: compilation, unit tests, plugin loader
graceful degradation, installed service validation, type declaration checks
validate-orchestrator-integration.yml (daily 3 AM UTC cron, ~1-2h):
- 5 parallel jobs mirroring orchestrator-integrity.yml:
plugin-interface, k8s (5 tests), aws (10 tests),
local-docker (9 tests), rclone (1 test)
- Full LocalStack + k3d integration coverage
- continue-on-error on known flaky end2end tests
* ci: add yarn.lock to validate-orchestrator path filters
Ensure orchestrator validation runs when yarn.lock changes, since
dependency updates can affect plugin compatibility.
* refactor: move install scripts to orchestrator repo
Install scripts now live at game-ci/orchestrator where the CLI releases
are published. Removed from unity-builder to avoid duplication.
* Potential fix for code scanning alert no. 78: Workflow does not contain permissions
* refactor: rename enterprise services to plugin services
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.
* fix(ci): update workflow references from loadEnterpriseServices to loadPluginServices
CI workflows still referenced the old function name after the rename.
* ci: remove (Nightly) from integration tests workflow name
* fix: only suppress module-not-found errors in plugin loader
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.
* ci: add smoke test for orchestrator build wiring
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.
* ci: wire orchestrator integration tests into integrity check
- 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
* fix(ci): pin LocalStack to v3.8.1 for AWS SDK v3 compatibility
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.
* revert: restore localstack:latest now that SDK is pinned
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.
* ci: reorder AWS integration tests to prevent workspace corruption
Move mandatory tests (caching, locking-core, locking-get-locked) before
continue-on-error e2e tests. The e2e tests can corrupt the workspace
(delete package.json), which was causing subsequent mandatory tests to
fail with "Couldn't find a package.json".
* refactor: plugin lifecycle interface for orchestrator extraction
Replace hardcoded orchestrator params with a lifecycle-based plugin
interface. The orchestrator reads its own config from env vars —
unity-builder just calls 6 hooks (initialize, canHandleBuild,
handleBuild, beforeLocalBuild, afterLocalBuild, handlePostBuild).
Removes ~2900 lines from unity-builder (93 BuildParameters fields,
346 Input getters, 70 action.yml inputs, 400 lines of service
orchestration in index.ts).
* fix: align CI workflow with actual loadOrchestratorPlugin export
The validate-orchestrator workflows referenced loadOrchestrator and
loadPluginServices which don't exist — the source exports
loadOrchestratorPlugin. Updated all CI steps to use the correct
function name and test the actual OrchestratorPlugin lifecycle interface.
* fix: checkout matching orchestrator branch in CI validation
The validate-orchestrator workflow was always checking out the main
branch of game-ci/orchestrator. When both repos have changes on a
feature branch (e.g. refactor/orchestrator-extraction), the CI needs
to use the matching branch. Falls back to main if the branch doesn't
exist in the orchestrator repo.
* ci: add run-integration label to trigger full integration tests on PRs
PRs labeled `run-integration` now run the full orchestrator integration
suite (K8s, AWS, local-docker, rclone via LocalStack + k3d). Without the
label, integration tests only run on push to main and the daily cron.
* ci: checkout matching orchestrator branch in integration tests
Try the matching branch name (e.g. refactor/orchestrator-extraction)
from game-ci/orchestrator first, falling back to main. This allows
testing cross-repo changes before merging to orchestrator main.
* ci: switch from LocalStack to MiniStack for AWS mock services
LocalStack community edition was discontinued (2026.03.0+) and now
requires a paid license for ECS, CloudFormation, Kinesis, and other
services used in integration tests.
Switch to MiniStack (MIT, free, ministackorg/ministack) which provides
all 40+ AWS services on the same port 4566 with backward-compatible
health endpoints. ~10x smaller image, ~2s startup.
* feat: add sync-secrets workflow for sibling repositories
Manually-triggered workflow that copies secrets (Unity credentials,
AWS/GCP tokens, Codecov) from unity-builder to orchestrator or cli repos.
Supports dry-run mode. Folded from PR #825.
* Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'
* fix: add UNITY_LICENSE and NPM_TOKEN to sync-secrets, don't block on failures
* chore: remove LOCALSTACK_AUTH_TOKEN from sync-secrets workflow
MiniStack doesn't require an auth token.
---------
… (#819)
* feat(orchestrator): enterprise feature support — CLI provider, submodule profiles, caching, LFS, hooks
Add generic enterprise-grade features to the orchestrator, enabling Unity projects with
complex CI/CD pipelines to adopt game-ci/unity-builder with built-in support for:
- CLI provider protocol: JSON-over-stdin/stdout bridge enabling providers in any language
(Go, Python, Rust, shell) via the `providerExecutable` input
- Submodule profiles: YAML-based selective submodule initialization with glob patterns
and variant overlays (`submoduleProfilePath`, `submoduleVariantPath`)
- Local build caching: Filesystem-based Library and LFS caching for local builds without
external cache actions (`localCacheEnabled`, `localCacheRoot`)
- Custom LFS transfer agents: Register external transfer agents like elastic-git-storage
(`lfsTransferAgent`, `lfsTransferAgentArgs`, `lfsStoragePaths`)
- Git hooks support: Detect and install lefthook/husky with configurable skip lists
(`gitHooksEnabled`, `gitHooksSkipList`)
Also removes all `orchestrator-develop` branch references, replacing with `main`.
13 new action inputs, 13 new files, 14 new CLI provider tests, 17 submodule tests,
plus cache/LFS/hooks unit tests. All 452 tests pass.
* feat(orchestrator): add experimental GCP Cloud Run and Azure ACI providers
Add two new cloud provider implementations for the orchestrator, both marked
as experimental:
- **GCP Cloud Run Jobs** (`providerStrategy: gcp-cloud-run`): Executes Unity
builds as Cloud Run Jobs with GCS FUSE for large artifact storage. Supports
configurable machine types, service accounts, and VPC connectors. 7 new inputs
(gcpProject, gcpRegion, gcpBucket, gcpMachineType, gcpDiskSizeGb,
gcpServiceAccount, gcpVpcConnector).
- **Azure Container Instances** (`providerStrategy: azure-aci`): Executes Unity
builds as ACI containers with Azure File Shares (Premium FileStorage) for
large artifact storage up to 100 TiB. Supports configurable CPU/memory,
VNet integration, and subscription targeting. 9 new inputs
(azureResourceGroup, azureLocation, azureStorageAccount, azureFileShareName,
azureSubscriptionId, azureCpu, azureMemoryGb, azureDiskSizeGb, azureSubnetId).
Both providers use their respective CLIs (gcloud, az) for infrastructure
management and support garbage collection of old build resources. No tests
included as these require real cloud infrastructure to validate.
* feat(orchestrator): multi-storage support for GCP and Azure providers
Both providers now support four storage backends via gcpStorageType / azureStorageType:
GCP Cloud Run:
- gcs-fuse: Mount GCS bucket as POSIX filesystem (unlimited, best for large sequential I/O)
- gcs-copy: Copy artifacts in/out via gsutil (simpler, no FUSE overhead)
- nfs: Filestore NFS mount (true POSIX, good random I/O, up to 100 TiB)
- in-memory: tmpfs (fastest, volatile, up to 32 GiB)
Azure ACI:
- azure-files: SMB file share mount (up to 100 TiB, premium throughput)
- blob-copy: Copy artifacts in/out via az storage blob (no mount overhead)
- azure-files-nfs: NFS 4.1 file share mount (true POSIX, no SMB lock overhead)
- in-memory: emptyDir tmpfs (fastest, volatile, limited by container memory)
New inputs: gcpStorageType, gcpFilestoreIp, gcpFilestoreShare, azureStorageType,
azureBlobContainer. Constructor validates storage config and warns on missing
prerequisites (e.g. NFS requires VPC connector/subnet).
* feat(orchestrator): automatic provider fallback with runner availability check
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.
* feat(orchestrator): add retry-on-fallback and provider init timeout
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.
* style: format changed files with prettier
* test(orchestrator): expand local cache service test coverage
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.
* test(orchestrator): add runner availability service tests
Covers: no token skip, no runners fallback, busy/offline runners,
label filtering (case-insensitive), minAvailable threshold,
fail-open on API error, mixed runner states.
* test(orchestrator): add unit tests for untested core services
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).
* ci(orchestrator): add fast unit test gate to integrity workflow
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.
* test(orchestrator): expand unit tests for enterprise services
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.
* fix(orchestrator): use http.extraHeader for secure git authentication
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
* feat(orchestrator): add premade secret sources and YAML definitions
Add SecretSourceService with premade secret source integrations:
- aws-secrets-manager (with --query SecretString for direct value)
- aws-parameter-store (with --with-decryption)
- gcp-secret-manager (latest version)
- azure-key-vault (via $AZURE_VAULT_NAME env var)
- env (environment variables, no shell command needed)
- Custom commands (any string with {0} placeholder)
- YAML file definitions for custom sources
Add secretSource input that takes precedence over inputPullCommand.
Backward compatible — existing inputPullCommand behavior unchanged.
Closes #776
* feat(secrets): add HashiCorp Vault as first-class premade secret source
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
* feat(lfs): add built-in elastic-git-storage support with auto-install
First-class support for elastic-git-storage as a custom LFS transfer
agent. When lfsTransferAgent is set to "elastic-git-storage" (or
"elastic-git-storage@v1.0.0" 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.
* feat(hooks): add Unity Git Hooks integration and runHookGroups
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.
* feat(orchestrator): add test workflow engine placeholder
Initial scaffold for the test workflow engine service directory.
* feat(orchestrator): add hot runner protocol placeholder
Initial scaffold for the runner registration and hot editor provider module.
* feat(orchestrator): generic artifact system — output types, manifests, and collection service
* feat(orchestrator): incremental sync protocol — git delta, direct input, and storage-backed sync
* feat: community plugin validation workflow (#800)
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
* feat(orchestrator): CI platform providers — Remote PowerShell, GitHub Actions, GitLab CI, Ansible
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.
* style: fix prettier formatting and eslint errors on test files
* feat(orchestrator): build reliability features — git integrity, reserved filename cleanup, archival
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.
* feat(reliability): implement build reliability service with git integrity, reserved filename cleanup, and build archival
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.
* test(providers): add comprehensive unit tests for GitHub Actions, GitLab CI, PowerShell, and Ansible providers (#806)
* feat(hot-runner): implement hot runner protocol with registry, health monitoring, and job dispatch (#791)
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
* feat(artifacts): complete generic artifact system with upload handlers, tests, and action integration (#798)
- 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
* feat(testing): implement test workflow engine with YAML suites, taxonomy filtering, and structured results (#790)
* feat(sync): complete incremental sync protocol with storage-pull, state management, and tests (#799)
- 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
* feat(cache): add child workspace isolation for multi-product CI builds (#777)
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.
* fix(testing): use async exec for parallel test group execution
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).
* fix(cli-provider): add timeout protection for external CLI processes
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
* fix(secrets): prevent shell injection in secret key names and mask values
- 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
* chore: rebuild dist for cli-provider timeout changes
* fix(artifacts): validate rclone availability before storage upload
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.
* fix(load-balancing): add pagination limits and rate-limit detection
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).
* fix(reliability): add disk space validation before build archival
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.
* fix(hot-runner): validate persisted registry state and add dispatcher safeguards
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.
* fix(providers): add polling timeouts, fix credential parsing, validate dependencies
- 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
* chore: rebuild dist for provider timeout and credential fixes
* fix: prettier formatting for orchestrator-folders-auth test
* ci: split orchestrator integrity into parallel jobs for faster validation
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
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* feat: add official game-ci CLI with build, activate, and orchestrate commands
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
* feat(cli): add npm publish workflow and CLI tests
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
* feat(cli): add release workflow, install scripts, and self-update command
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.
* fix(cli): address review findings — exit codes, missing inputs, null safety
- Add process.exit(1) in cli.ts catch block so failures produce non-zero exit codes
- Add 6 missing build inputs: containerRegistryRepository, containerRegistryImageVersion,
dockerIsolationMode, sshPublicKeysDirectoryPath, cacheUnityInstallationOnMac, unityHubVersionOnMac
- Add 6 missing orchestrate inputs: kubeStorageClass, readInputFromOverrideList,
readInputOverrideCommand, postBuildSteps, preBuildSteps, customJob
- Fix activate command description to accurately reflect verification behavior
- Add null check before accessing result.BuildResults in orchestrate handler
* ci: split orchestrator integrity into 4 parallel jobs to fix timeout
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.
* chore: add integration branch update scripts for release/lts-2.0.0
* ci: set macOS builds to continue-on-error
* chore: add release/lts-infrastructure to update-all script
* ci: set macOS builds to continue-on-error
* fix: make git hooks opt-in only — do not modify hooks when disabled
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.
* test: add integration wiring and input parsing tests for enterprise features
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.
* ci: mark failed macOS builds as neutral instead of failure
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.
* revert: restore build-tests-mac.yml to match main
Stop modifying the macOS build workflow — leave it identical to main.
* fix(test): add gitAuthMode to orchestrator-folders test mock
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.
* fix(ci): bump node version to 20 in integrity-check
yargs@18.0.0 requires Node >=20.19.0, so Node 18 is no longer
compatible.
* fix: downgrade yargs to ^17.7.2 and revert Node to 18 for CI compatibility
yargs@18 requires Node >=20.19.0 which is incompatible with CI's Node 18.
* refactor(cli): move cache command under orchestrate subcommand
Cache is an orchestrator feature, so it belongs under `game-ci orchestrate cache`
rather than as a top-level `game-ci cache` command.
* ci: add orchestrator compatibility validation workflow
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
* refactor: route orchestrator through plugin loader
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.
* refactor: extract orchestrator — delete 30k lines, decouple all imports
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.
* refactor: move CLI to orchestrator, fix validate-orchestrator workflow
- 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.
* fix(ci): remove reference to deleted orchestrator-integrity.yml
The orchestrator job in integrity-check.yml called the deleted
orchestrator-integrity.yml workflow, causing CI failure.
* fix(ci): use --legacy-peer-deps for orchestrator install in validation
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.
* chore: remove temporary delete-me scripts
* feat(ci): add orchestrator integration tests and plugin interface tests
- 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)
* fix(ci): add build step to k8s and aws integration jobs
The orchestrator tests need compiled output (dist/index.js) to exist
before running integration tests that spawn containers/k8s jobs.
* fix(ci): add refactor/** branch pattern and workflow_dispatch to orchestrator workflows
The refactor/orchestrator-extraction branch was not matching the
feature/** pattern, preventing the integration workflow from running
after fix commits were pushed.
* refactor(ci): split orchestrator tests into per-PR health checks and nightly exhaustive suite
validate-orchestrator.yml (per-PR, ~5 min):
- Plugin architecture health: compilation, unit tests, plugin loader
graceful degradation, installed service validation, type declaration checks
validate-orchestrator-integration.yml (daily 3 AM UTC cron, ~1-2h):
- 5 parallel jobs mirroring orchestrator-integrity.yml:
plugin-interface, k8s (5 tests), aws (10 tests),
local-docker (9 tests), rclone (1 test)
- Full LocalStack + k3d integration coverage
- continue-on-error on known flaky end2end tests
* ci: add yarn.lock to validate-orchestrator path filters
Ensure orchestrator validation runs when yarn.lock changes, since
dependency updates can affect plugin compatibility.
* refactor: move install scripts to orchestrator repo
Install scripts now live at game-ci/orchestrator where the CLI releases
are published. Removed from unity-builder to avoid duplication.
* Potential fix for code scanning alert no. 78: Workflow does not contain permissions
* refactor: rename enterprise services to plugin services
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.
* fix(ci): update workflow references from loadEnterpriseServices to loadPluginServices
CI workflows still referenced the old function name after the rename.
* ci: remove (Nightly) from integration tests workflow name
* fix: only suppress module-not-found errors in plugin loader
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.
* ci: add smoke test for orchestrator build wiring
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.
* ci: wire orchestrator integration tests into integrity check
- 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
* fix(ci): pin LocalStack to v3.8.1 for AWS SDK v3 compatibility
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.
* revert: restore localstack:latest now that SDK is pinned
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.
* ci: reorder AWS integration tests to prevent workspace corruption
Move mandatory tests (caching, locking-core, locking-get-locked) before
continue-on-error e2e tests. The e2e tests can corrupt the workspace
(delete package.json), which was causing subsequent mandatory tests to
fail with "Couldn't find a package.json".
* refactor: plugin lifecycle interface for orchestrator extraction
Replace hardcoded orchestrator params with a lifecycle-based plugin
interface. The orchestrator reads its own config from env vars —
unity-builder just calls 6 hooks (initialize, canHandleBuild,
handleBuild, beforeLocalBuild, afterLocalBuild, handlePostBuild).
Removes ~2900 lines from unity-builder (93 BuildParameters fields,
346 Input getters, 70 action.yml inputs, 400 lines of service
orchestration in index.ts).
* fix: align CI workflow with actual loadOrchestratorPlugin export
The validate-orchestrator workflows referenced loadOrchestrator and
loadPluginServices which don't exist — the source exports
loadOrchestratorPlugin. Updated all CI steps to use the correct
function name and test the actual OrchestratorPlugin lifecycle interface.
* fix: checkout matching orchestrator branch in CI validation
The validate-orchestrator workflow was always checking out the main
branch of game-ci/orchestrator. When both repos have changes on a
feature branch (e.g. refactor/orchestrator-extraction), the CI needs
to use the matching branch. Falls back to main if the branch doesn't
exist in the orchestrator repo.
* ci: add run-integration label to trigger full integration tests on PRs
PRs labeled `run-integration` now run the full orchestrator integration
suite (K8s, AWS, local-docker, rclone via LocalStack + k3d). Without the
label, integration tests only run on push to main and the daily cron.
* ci: checkout matching orchestrator branch in integration tests
Try the matching branch name (e.g. refactor/orchestrator-extraction)
from game-ci/orchestrator first, falling back to main. This allows
testing cross-repo changes before merging to orchestrator main.
* ci: switch from LocalStack to MiniStack for AWS mock services
LocalStack community edition was discontinued (2026.03.0+) and now
requires a paid license for ECS, CloudFormation, Kinesis, and other
services used in integration tests.
Switch to MiniStack (MIT, free, ministackorg/ministack) which provides
all 40+ AWS services on the same port 4566 with backward-compatible
health endpoints. ~10x smaller image, ~2s startup.
* feat: add sync-secrets workflow for sibling repositories
Manually-triggered workflow that copies secrets (Unity credentials,
AWS/GCP tokens, Codecov) from unity-builder to orchestrator or cli repos.
Supports dry-run mode. Folded from PR #825.
* Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'
* fix: add UNITY_LICENSE and NPM_TOKEN to sync-secrets, don't block on failures
* chore: remove LOCALSTACK_AUTH_TOKEN from sync-secrets workflow
MiniStack doesn't require an auth token.
---------
… (#819)
* feat(orchestrator): enterprise feature support — CLI provider, submodule profiles, caching, LFS, hooks
Add generic enterprise-grade features to the orchestrator, enabling Unity projects with
complex CI/CD pipelines to adopt game-ci/unity-builder with built-in support for:
- CLI provider protocol: JSON-over-stdin/stdout bridge enabling providers in any language
(Go, Python, Rust, shell) via the `providerExecutable` input
- Submodule profiles: YAML-based selective submodule initialization with glob patterns
and variant overlays (`submoduleProfilePath`, `submoduleVariantPath`)
- Local build caching: Filesystem-based Library and LFS caching for local builds without
external cache actions (`localCacheEnabled`, `localCacheRoot`)
- Custom LFS transfer agents: Register external transfer agents like elastic-git-storage
(`lfsTransferAgent`, `lfsTransferAgentArgs`, `lfsStoragePaths`)
- Git hooks support: Detect and install lefthook/husky with configurable skip lists
(`gitHooksEnabled`, `gitHooksSkipList`)
Also removes all `orchestrator-develop` branch references, replacing with `main`.
13 new action inputs, 13 new files, 14 new CLI provider tests, 17 submodule tests,
plus cache/LFS/hooks unit tests. All 452 tests pass.
* feat(orchestrator): add experimental GCP Cloud Run and Azure ACI providers
Add two new cloud provider implementations for the orchestrator, both marked
as experimental:
- **GCP Cloud Run Jobs** (`providerStrategy: gcp-cloud-run`): Executes Unity
builds as Cloud Run Jobs with GCS FUSE for large artifact storage. Supports
configurable machine types, service accounts, and VPC connectors. 7 new inputs
(gcpProject, gcpRegion, gcpBucket, gcpMachineType, gcpDiskSizeGb,
gcpServiceAccount, gcpVpcConnector).
- **Azure Container Instances** (`providerStrategy: azure-aci`): Executes Unity
builds as ACI containers with Azure File Shares (Premium FileStorage) for
large artifact storage up to 100 TiB. Supports configurable CPU/memory,
VNet integration, and subscription targeting. 9 new inputs
(azureResourceGroup, azureLocation, azureStorageAccount, azureFileShareName,
azureSubscriptionId, azureCpu, azureMemoryGb, azureDiskSizeGb, azureSubnetId).
Both providers use their respective CLIs (gcloud, az) for infrastructure
management and support garbage collection of old build resources. No tests
included as these require real cloud infrastructure to validate.
* feat(orchestrator): multi-storage support for GCP and Azure providers
Both providers now support four storage backends via gcpStorageType / azureStorageType:
GCP Cloud Run:
- gcs-fuse: Mount GCS bucket as POSIX filesystem (unlimited, best for large sequential I/O)
- gcs-copy: Copy artifacts in/out via gsutil (simpler, no FUSE overhead)
- nfs: Filestore NFS mount (true POSIX, good random I/O, up to 100 TiB)
- in-memory: tmpfs (fastest, volatile, up to 32 GiB)
Azure ACI:
- azure-files: SMB file share mount (up to 100 TiB, premium throughput)
- blob-copy: Copy artifacts in/out via az storage blob (no mount overhead)
- azure-files-nfs: NFS 4.1 file share mount (true POSIX, no SMB lock overhead)
- in-memory: emptyDir tmpfs (fastest, volatile, limited by container memory)
New inputs: gcpStorageType, gcpFilestoreIp, gcpFilestoreShare, azureStorageType,
azureBlobContainer. Constructor validates storage config and warns on missing
prerequisites (e.g. NFS requires VPC connector/subnet).
* feat(orchestrator): automatic provider fallback with runner availability check
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.
* feat(orchestrator): add retry-on-fallback and provider init timeout
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.
* style: format changed files with prettier
* test(orchestrator): expand local cache service test coverage
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.
* test(orchestrator): add runner availability service tests
Covers: no token skip, no runners fallback, busy/offline runners,
label filtering (case-insensitive), minAvailable threshold,
fail-open on API error, mixed runner states.
* test(orchestrator): add unit tests for untested core services
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).
* ci(orchestrator): add fast unit test gate to integrity workflow
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.
* test(orchestrator): expand unit tests for enterprise services
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.
* fix(orchestrator): use http.extraHeader for secure git authentication
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
* feat(orchestrator): add premade secret sources and YAML definitions
Add SecretSourceService with premade secret source integrations:
- aws-secrets-manager (with --query SecretString for direct value)
- aws-parameter-store (with --with-decryption)
- gcp-secret-manager (latest version)
- azure-key-vault (via $AZURE_VAULT_NAME env var)
- env (environment variables, no shell command needed)
- Custom commands (any string with {0} placeholder)
- YAML file definitions for custom sources
Add secretSource input that takes precedence over inputPullCommand.
Backward compatible — existing inputPullCommand behavior unchanged.
Closes #776
* feat(secrets): add HashiCorp Vault as first-class premade secret source
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
* feat(lfs): add built-in elastic-git-storage support with auto-install
First-class support for elastic-git-storage as a custom LFS transfer
agent. When lfsTransferAgent is set to "elastic-git-storage" (or
"elastic-git-storage@v1.0.0" 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.
* feat(hooks): add Unity Git Hooks integration and runHookGroups
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.
* feat(orchestrator): add test workflow engine placeholder
Initial scaffold for the test workflow engine service directory.
* feat(orchestrator): add hot runner protocol placeholder
Initial scaffold for the runner registration and hot editor provider module.
* feat(orchestrator): generic artifact system — output types, manifests, and collection service
* feat(orchestrator): incremental sync protocol — git delta, direct input, and storage-backed sync
* feat: community plugin validation workflow (#800)
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
* feat(orchestrator): CI platform providers — Remote PowerShell, GitHub Actions, GitLab CI, Ansible
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.
* style: fix prettier formatting and eslint errors on test files
* feat(orchestrator): build reliability features — git integrity, reserved filename cleanup, archival
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.
* feat(reliability): implement build reliability service with git integrity, reserved filename cleanup, and build archival
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.
* test(providers): add comprehensive unit tests for GitHub Actions, GitLab CI, PowerShell, and Ansible providers (#806)
* feat(hot-runner): implement hot runner protocol with registry, health monitoring, and job dispatch (#791)
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
* feat(artifacts): complete generic artifact system with upload handlers, tests, and action integration (#798)
- 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
* feat(testing): implement test workflow engine with YAML suites, taxonomy filtering, and structured results (#790)
* feat(sync): complete incremental sync protocol with storage-pull, state management, and tests (#799)
- 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
* feat(cache): add child workspace isolation for multi-product CI builds (#777)
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.
* fix(testing): use async exec for parallel test group execution
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).
* fix(cli-provider): add timeout protection for external CLI processes
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
* fix(secrets): prevent shell injection in secret key names and mask values
- 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
* chore: rebuild dist for cli-provider timeout changes
* fix(artifacts): validate rclone availability before storage upload
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.
* fix(load-balancing): add pagination limits and rate-limit detection
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).
* fix(reliability): add disk space validation before build archival
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.
* fix(hot-runner): validate persisted registry state and add dispatcher safeguards
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.
* fix(providers): add polling timeouts, fix credential parsing, validate dependencies
- 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
* chore: rebuild dist for provider timeout and credential fixes
* fix: prettier formatting for orchestrator-folders-auth test
* ci: split orchestrator integrity into parallel jobs for faster validation
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
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* style: fix prettier formatting
* feat: add official game-ci CLI with build, activate, and orchestrate commands
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
* feat(cli): add npm publish workflow and CLI tests
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
* feat(cli): add release workflow, install scripts, and self-update command
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.
* fix(cli): address review findings — exit codes, missing inputs, null safety
- Add process.exit(1) in cli.ts catch block so failures produce non-zero exit codes
- Add 6 missing build inputs: containerRegistryRepository, containerRegistryImageVersion,
dockerIsolationMode, sshPublicKeysDirectoryPath, cacheUnityInstallationOnMac, unityHubVersionOnMac
- Add 6 missing orchestrate inputs: kubeStorageClass, readInputFromOverrideList,
readInputOverrideCommand, postBuildSteps, preBuildSteps, customJob
- Fix activate command description to accurately reflect verification behavior
- Add null check before accessing result.BuildResults in orchestrate handler
* ci: split orchestrator integrity into 4 parallel jobs to fix timeout
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.
* chore: add integration branch update scripts for release/lts-2.0.0
* ci: set macOS builds to continue-on-error
* chore: add release/lts-infrastructure to update-all script
* ci: set macOS builds to continue-on-error
* fix: make git hooks opt-in only — do not modify hooks when disabled
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.
* test: add integration wiring and input parsing tests for enterprise features
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.
* ci: mark failed macOS builds as neutral instead of failure
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.
* revert: restore build-tests-mac.yml to match main
Stop modifying the macOS build workflow — leave it identical to main.
* fix(test): add gitAuthMode to orchestrator-folders test mock
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.
* fix(ci): bump node version to 20 in integrity-check
yargs@18.0.0 requires Node >=20.19.0, so Node 18 is no longer
compatible.
* fix: downgrade yargs to ^17.7.2 and revert Node to 18 for CI compatibility
yargs@18 requires Node >=20.19.0 which is incompatible with CI's Node 18.
* refactor(cli): move cache command under orchestrate subcommand
Cache is an orchestrator feature, so it belongs under `game-ci orchestrate cache`
rather than as a top-level `game-ci cache` command.
* ci: add orchestrator compatibility validation workflow
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
* refactor: route orchestrator through plugin loader
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.
* refactor: extract orchestrator — delete 30k lines, decouple all imports
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.
* refactor: move CLI to orchestrator, fix validate-orchestrator workflow
- 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.
* fix(ci): remove reference to deleted orchestrator-integrity.yml
The orchestrator job in integrity-check.yml called the deleted
orchestrator-integrity.yml workflow, causing CI failure.
* fix(ci): use --legacy-peer-deps for orchestrator install in validation
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.
* chore: remove temporary delete-me scripts
* feat(ci): add orchestrator integration tests and plugin interface tests
- 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)
* fix(ci): add build step to k8s and aws integration jobs
The orchestrator tests need compiled output (dist/index.js) to exist
before running integration tests that spawn containers/k8s jobs.
* fix(ci): add refactor/** branch pattern and workflow_dispatch to orchestrator workflows
The refactor/orchestrator-extraction branch was not matching the
feature/** pattern, preventing the integration workflow from running
after fix commits were pushed.
* refactor(ci): split orchestrator tests into per-PR health checks and nightly exhaustive suite
validate-orchestrator.yml (per-PR, ~5 min):
- Plugin architecture health: compilation, unit tests, plugin loader
graceful degradation, installed service validation, type declaration checks
validate-orchestrator-integration.yml (daily 3 AM UTC cron, ~1-2h):
- 5 parallel jobs mirroring orchestrator-integrity.yml:
plugin-interface, k8s (5 tests), aws (10 tests),
local-docker (9 tests), rclone (1 test)
- Full LocalStack + k3d integration coverage
- continue-on-error on known flaky end2end tests
* ci: add yarn.lock to validate-orchestrator path filters
Ensure orchestrator validation runs when yarn.lock changes, since
dependency updates can affect plugin compatibility.
* refactor: move install scripts to orchestrator repo
Install scripts now live at game-ci/orchestrator where the CLI releases
are published. Removed from unity-builder to avoid duplication.
* Potential fix for code scanning alert no. 78: Workflow does not contain permissions
* refactor: rename enterprise services to plugin services
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.
* fix(ci): update workflow references from loadEnterpriseServices to loadPluginServices
CI workflows still referenced the old function name after the rename.
* ci: remove (Nightly) from integration tests workflow name
* fix: only suppress module-not-found errors in plugin loader
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.
* ci: add smoke test for orchestrator build wiring
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.
* ci: wire orchestrator integration tests into integrity check
- 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
* fix(ci): pin LocalStack to v3.8.1 for AWS SDK v3 compatibility
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.
* revert: restore localstack:latest now that SDK is pinned
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.
* ci: reorder AWS integration tests to prevent workspace corruption
Move mandatory tests (caching, locking-core, locking-get-locked) before
continue-on-error e2e tests. The e2e tests can corrupt the workspace
(delete package.json), which was causing subsequent mandatory tests to
fail with "Couldn't find a package.json".
* refactor: plugin lifecycle interface for orchestrator extraction
Replace hardcoded orchestrator params with a lifecycle-based plugin
interface. The orchestrator reads its own config from env vars —
unity-builder just calls 6 hooks (initialize, canHandleBuild,
handleBuild, beforeLocalBuild, afterLocalBuild, handlePostBuild).
Removes ~2900 lines from unity-builder (93 BuildParameters fields,
346 Input getters, 70 action.yml inputs, 400 lines of service
orchestration in index.ts).
* fix: align CI workflow with actual loadOrchestratorPlugin export
The validate-orchestrator workflows referenced loadOrchestrator and
loadPluginServices which don't exist — the source exports
loadOrchestratorPlugin. Updated all CI steps to use the correct
function name and test the actual OrchestratorPlugin lifecycle interface.
* fix: checkout matching orchestrator branch in CI validation
The validate-orchestrator workflow was always checking out the main
branch of game-ci/orchestrator. When both repos have changes on a
feature branch (e.g. refactor/orchestrator-extraction), the CI needs
to use the matching branch. Falls back to main if the branch doesn't
exist in the orchestrator repo.
* ci: add run-integration label to trigger full integration tests on PRs
PRs labeled `run-integration` now run the full orchestrator integration
suite (K8s, AWS, local-docker, rclone via LocalStack + k3d). Without the
label, integration tests only run on push to main and the daily cron.
* ci: checkout matching orchestrator branch in integration tests
Try the matching branch name (e.g. refactor/orchestrator-extraction)
from game-ci/orchestrator first, falling back to main. This allows
testing cross-repo changes before merging to orchestrator main.
* ci: switch from LocalStack to MiniStack for AWS mock services
LocalStack community edition was discontinued (2026.03.0+) and now
requires a paid license for ECS, CloudFormation, Kinesis, and other
services used in integration tests.
Switch to MiniStack (MIT, free, ministackorg/ministack) which provides
all 40+ AWS services on the same port 4566 with backward-compatible
health endpoints. ~10x smaller image, ~2s startup.
* feat: add sync-secrets workflow for sibling repositories
Manually-triggered workflow that copies secrets (Unity credentials,
AWS/GCP tokens, Codecov) from unity-builder to orchestrator or cli repos.
Supports dry-run mode. Folded from PR #825.
* Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'
* fix: add UNITY_LICENSE and NPM_TOKEN to sync-secrets, don't block on failures
* chore: remove LOCALSTACK_AUTH_TOKEN from sync-secrets workflow
MiniStack doesn't require an auth token.
---------
…tionlint) (#833) * chore: quality-tightening (oxfmt + oxlint + tsc + vitest + husky + actionlint) Standard rollout for unity-builder. Most of the work was porting 24 test files from jest 27 to vitest 4. - prettier -> oxfmt - eslint (with @typescript-eslint, github, jest, prettier, unicorn) -> oxlint with eslint-plugin-unicorn - jest 27 + jest-circus + ts-jest + @types/jest + @jest/globals -> vitest 4 + vite 7 + @vitest/coverage-istanbul (jest config files removed) - new: tsgo --noEmit (alongside tsc fallback) - lefthook (and lefthook.yml) -> husky 9 with the standard scripts/ensure-husky.mjs self-heal pattern + lint-staged - new: gitleaks, actionlint, shellcheck as mise-managed binaries - TypeScript bumped target ES2020 -> ES2022 + lib ES2022 + DOM (for Error.cause and modern globals) Test migration (24 files): - Bulk-converted jest.* -> vi.*; jest.Mocked -> Mocked from vitest; jest.MockedFunction -> MockedFunction. - Added vitest imports to all *.test.ts files (and __mocks__/*.ts) that didn't have them. - src/index.ts: extracted runMain() as a named export and gated the module-level invocation behind NODE_ENV !== 'test'. The index-plugin-features test now calls runMain() directly instead of relying on jest's removed vi.isolateModules. - index-plugin-features.test.ts: moved hoisted refs (mockPlugin, mockLoadOrchestratorPlugin) into vi.hoisted() so vi.mock factories can reference them. Replaced arrow constructor mock for ImageTag with regular function() {...} (vitest 4 disallows arrows as ctors). Replaced require('./model') / require('@actions/core') inside test bodies with top-level imports. - model/orchestrator-plugin.test.ts: dropped jest's '{ virtual: true }' flag (vitest doesn't support it); replaced the 'mock factory throws' pattern with 'createPlugin throws' so vitest doesn't wrap the error message at the assertion site. - model/versioning.test.ts: stray jest.spyOn -> vi.spyOn; replaced mockImplementation() with no args (jest pattern) by mockResolvedValue('') / mockImplementation(() => undefined) where the source expects a string return. Workflow shell-quoting cleanup (actionlint): - All bare $GITHUB_STEP_SUMMARY / $GITHUB_OUTPUT / $GITHUB_ENV redirects quoted across 2 workflows (SC2086). - s3://$AWS_STACK_NAME / s3://$BUCKET_NAME -> s3://"$AWS_STACK_NAME" / s3://"$BUCKET_NAME". - 'for i in {1..N}; do ... done' loops where i isn't referenced in the body renamed to 'for _ in' (SC2034). - 'grep ... | wc -l' -> 'grep -c ...' (SC2126). - Multiple consecutive '>> $file' redirects in validate-community-plugins.yml summary block collapsed into a single block redirect (SC2129). - 'cat $file | python3 -c "..."' -> 'python3 -c "..." < $file' (SC2002). - http://${VAR}:port -> http://"${VAR}":port (SC2086). tsgo: kept tsc --noEmit as the default 'typecheck' because unity-builder publishes CommonJS for the GitHub Action consumer, which conflicts with tsgo's bundler/node16 moduleResolution requirement (per playbook trap #9). 'yarn typecheck:tsgo' is wired up for when consumers move to ESM. Caveats: 28 pre-existing oxlint warnings remain (mostly typescript/no-explicit-any across the build-parameter shapes and vitest/no-disabled-tests on 2 explicitly skipped scenarios). Per playbook trap #22 the lint script drops --deny-warnings. Verified locally: format clean, lint 0/28, typecheck clean, test 340/342 (2 pre-existing skipped), actionlint clean across all 12 workflows. * ci(unity-builder): fix Tests + Plugin Architecture Health on quality-tightening Three issues surfaced in CI after the jest -> vitest port: 1. **Obsolete snapshot blocks Tests job.** src/model/__snapshots__/versioning.test.ts.snap had two entries for the same 'throws for invalid strategy' assertion: one in the vitest format ('Versioning > determineBuildVersion > ...') and one in the legacy jest format without the '>'. vitest correctly regenerates the new one and flags the old one as obsolete; CI runs without --update so 'Test Files 1 failed' even though all 343 tests passed. Removed the obsolete entry. 2. **'Plugin Architecture Health' workflow still calls jest.** .github/workflows/validate-orchestrator.yml had two 'npx jest' steps (orchestrator-plugin unit tests + orchestrator-standalone tests). The unity-builder + orchestrator codebases are both on vitest now. Replaced both with 'yarn vitest run'. 3. **jest-fail-on-console + src/jest.setup.ts left over.** The earlier vitest port missed the jest-fail-on-console integration. yarn install in CI surfaced YN0002: doesn't provide @jest/globals (requested by jest-fail-on-console). Removed jest-fail-on-console + jest.setup.ts; added src/test/setup.ts with the equivalent vitest beforeEach spies (same as unity-test-runner). ---------
…tionlint) (#833) * chore: quality-tightening (oxfmt + oxlint + tsc + vitest + husky + actionlint) Standard rollout for unity-builder. Most of the work was porting 24 test files from jest 27 to vitest 4. - prettier -> oxfmt - eslint (with @typescript-eslint, github, jest, prettier, unicorn) -> oxlint with eslint-plugin-unicorn - jest 27 + jest-circus + ts-jest + @types/jest + @jest/globals -> vitest 4 + vite 7 + @vitest/coverage-istanbul (jest config files removed) - new: tsgo --noEmit (alongside tsc fallback) - lefthook (and lefthook.yml) -> husky 9 with the standard scripts/ensure-husky.mjs self-heal pattern + lint-staged - new: gitleaks, actionlint, shellcheck as mise-managed binaries - TypeScript bumped target ES2020 -> ES2022 + lib ES2022 + DOM (for Error.cause and modern globals) Test migration (24 files): - Bulk-converted jest.* -> vi.*; jest.Mocked -> Mocked from vitest; jest.MockedFunction -> MockedFunction. - Added vitest imports to all *.test.ts files (and __mocks__/*.ts) that didn't have them. - src/index.ts: extracted runMain() as a named export and gated the module-level invocation behind NODE_ENV !== 'test'. The index-plugin-features test now calls runMain() directly instead of relying on jest's removed vi.isolateModules. - index-plugin-features.test.ts: moved hoisted refs (mockPlugin, mockLoadOrchestratorPlugin) into vi.hoisted() so vi.mock factories can reference them. Replaced arrow constructor mock for ImageTag with regular function() {...} (vitest 4 disallows arrows as ctors). Replaced require('./model') / require('@actions/core') inside test bodies with top-level imports. - model/orchestrator-plugin.test.ts: dropped jest's '{ virtual: true }' flag (vitest doesn't support it); replaced the 'mock factory throws' pattern with 'createPlugin throws' so vitest doesn't wrap the error message at the assertion site. - model/versioning.test.ts: stray jest.spyOn -> vi.spyOn; replaced mockImplementation() with no args (jest pattern) by mockResolvedValue('') / mockImplementation(() => undefined) where the source expects a string return. Workflow shell-quoting cleanup (actionlint): - All bare $GITHUB_STEP_SUMMARY / $GITHUB_OUTPUT / $GITHUB_ENV redirects quoted across 2 workflows (SC2086). - s3://$AWS_STACK_NAME / s3://$BUCKET_NAME -> s3://"$AWS_STACK_NAME" / s3://"$BUCKET_NAME". - 'for i in {1..N}; do ... done' loops where i isn't referenced in the body renamed to 'for _ in' (SC2034). - 'grep ... | wc -l' -> 'grep -c ...' (SC2126). - Multiple consecutive '>> $file' redirects in validate-community-plugins.yml summary block collapsed into a single block redirect (SC2129). - 'cat $file | python3 -c "..."' -> 'python3 -c "..." < $file' (SC2002). - http://${VAR}:port -> http://"${VAR}":port (SC2086). tsgo: kept tsc --noEmit as the default 'typecheck' because unity-builder publishes CommonJS for the GitHub Action consumer, which conflicts with tsgo's bundler/node16 moduleResolution requirement (per playbook trap #9). 'yarn typecheck:tsgo' is wired up for when consumers move to ESM. Caveats: 28 pre-existing oxlint warnings remain (mostly typescript/no-explicit-any across the build-parameter shapes and vitest/no-disabled-tests on 2 explicitly skipped scenarios). Per playbook trap #22 the lint script drops --deny-warnings. Verified locally: format clean, lint 0/28, typecheck clean, test 340/342 (2 pre-existing skipped), actionlint clean across all 12 workflows. * ci(unity-builder): fix Tests + Plugin Architecture Health on quality-tightening Three issues surfaced in CI after the jest -> vitest port: 1. **Obsolete snapshot blocks Tests job.** src/model/__snapshots__/versioning.test.ts.snap had two entries for the same 'throws for invalid strategy' assertion: one in the vitest format ('Versioning > determineBuildVersion > ...') and one in the legacy jest format without the '>'. vitest correctly regenerates the new one and flags the old one as obsolete; CI runs without --update so 'Test Files 1 failed' even though all 343 tests passed. Removed the obsolete entry. 2. **'Plugin Architecture Health' workflow still calls jest.** .github/workflows/validate-orchestrator.yml had two 'npx jest' steps (orchestrator-plugin unit tests + orchestrator-standalone tests). The unity-builder + orchestrator codebases are both on vitest now. Replaced both with 'yarn vitest run'. 3. **jest-fail-on-console + src/jest.setup.ts left over.** The earlier vitest port missed the jest-fail-on-console integration. yarn install in CI surfaced YN0002: doesn't provide @jest/globals (requested by jest-fail-on-console). Removed jest-fail-on-console + jest.setup.ts; added src/test/setup.ts with the equivalent vitest beforeEach spies (same as unity-test-runner). ---------
…tionlint) (#833) * chore: quality-tightening (oxfmt + oxlint + tsc + vitest + husky + actionlint) Standard rollout for unity-builder. Most of the work was porting 24 test files from jest 27 to vitest 4. - prettier -> oxfmt - eslint (with @typescript-eslint, github, jest, prettier, unicorn) -> oxlint with eslint-plugin-unicorn - jest 27 + jest-circus + ts-jest + @types/jest + @jest/globals -> vitest 4 + vite 7 + @vitest/coverage-istanbul (jest config files removed) - new: tsgo --noEmit (alongside tsc fallback) - lefthook (and lefthook.yml) -> husky 9 with the standard scripts/ensure-husky.mjs self-heal pattern + lint-staged - new: gitleaks, actionlint, shellcheck as mise-managed binaries - TypeScript bumped target ES2020 -> ES2022 + lib ES2022 + DOM (for Error.cause and modern globals) Test migration (24 files): - Bulk-converted jest.* -> vi.*; jest.Mocked -> Mocked from vitest; jest.MockedFunction -> MockedFunction. - Added vitest imports to all *.test.ts files (and __mocks__/*.ts) that didn't have them. - src/index.ts: extracted runMain() as a named export and gated the module-level invocation behind NODE_ENV !== 'test'. The index-plugin-features test now calls runMain() directly instead of relying on jest's removed vi.isolateModules. - index-plugin-features.test.ts: moved hoisted refs (mockPlugin, mockLoadOrchestratorPlugin) into vi.hoisted() so vi.mock factories can reference them. Replaced arrow constructor mock for ImageTag with regular function() {...} (vitest 4 disallows arrows as ctors). Replaced require('./model') / require('@actions/core') inside test bodies with top-level imports. - model/orchestrator-plugin.test.ts: dropped jest's '{ virtual: true }' flag (vitest doesn't support it); replaced the 'mock factory throws' pattern with 'createPlugin throws' so vitest doesn't wrap the error message at the assertion site. - model/versioning.test.ts: stray jest.spyOn -> vi.spyOn; replaced mockImplementation() with no args (jest pattern) by mockResolvedValue('') / mockImplementation(() => undefined) where the source expects a string return. Workflow shell-quoting cleanup (actionlint): - All bare $GITHUB_STEP_SUMMARY / $GITHUB_OUTPUT / $GITHUB_ENV redirects quoted across 2 workflows (SC2086). - s3://$AWS_STACK_NAME / s3://$BUCKET_NAME -> s3://"$AWS_STACK_NAME" / s3://"$BUCKET_NAME". - 'for i in {1..N}; do ... done' loops where i isn't referenced in the body renamed to 'for _ in' (SC2034). - 'grep ... | wc -l' -> 'grep -c ...' (SC2126). - Multiple consecutive '>> $file' redirects in validate-community-plugins.yml summary block collapsed into a single block redirect (SC2129). - 'cat $file | python3 -c "..."' -> 'python3 -c "..." < $file' (SC2002). - http://${VAR}:port -> http://"${VAR}":port (SC2086). tsgo: kept tsc --noEmit as the default 'typecheck' because unity-builder publishes CommonJS for the GitHub Action consumer, which conflicts with tsgo's bundler/node16 moduleResolution requirement (per playbook trap #9). 'yarn typecheck:tsgo' is wired up for when consumers move to ESM. Caveats: 28 pre-existing oxlint warnings remain (mostly typescript/no-explicit-any across the build-parameter shapes and vitest/no-disabled-tests on 2 explicitly skipped scenarios). Per playbook trap #22 the lint script drops --deny-warnings. Verified locally: format clean, lint 0/28, typecheck clean, test 340/342 (2 pre-existing skipped), actionlint clean across all 12 workflows. * ci(unity-builder): fix Tests + Plugin Architecture Health on quality-tightening Three issues surfaced in CI after the jest -> vitest port: 1. **Obsolete snapshot blocks Tests job.** src/model/__snapshots__/versioning.test.ts.snap had two entries for the same 'throws for invalid strategy' assertion: one in the vitest format ('Versioning > determineBuildVersion > ...') and one in the legacy jest format without the '>'. vitest correctly regenerates the new one and flags the old one as obsolete; CI runs without --update so 'Test Files 1 failed' even though all 343 tests passed. Removed the obsolete entry. 2. **'Plugin Architecture Health' workflow still calls jest.** .github/workflows/validate-orchestrator.yml had two 'npx jest' steps (orchestrator-plugin unit tests + orchestrator-standalone tests). The unity-builder + orchestrator codebases are both on vitest now. Replaced both with 'yarn vitest run'. 3. **jest-fail-on-console + src/jest.setup.ts left over.** The earlier vitest port missed the jest-fail-on-console integration. yarn install in CI surfaced YN0002: doesn't provide @jest/globals (requested by jest-fail-on-console). Removed jest-fail-on-console + jest.setup.ts; added src/test/setup.ts with the equivalent vitest beforeEach spies (same as unity-test-runner). ---------
…tionlint) (#833) * chore: quality-tightening (oxfmt + oxlint + tsc + vitest + husky + actionlint) Standard rollout for unity-builder. Most of the work was porting 24 test files from jest 27 to vitest 4. - prettier -> oxfmt - eslint (with @typescript-eslint, github, jest, prettier, unicorn) -> oxlint with eslint-plugin-unicorn - jest 27 + jest-circus + ts-jest + @types/jest + @jest/globals -> vitest 4 + vite 7 + @vitest/coverage-istanbul (jest config files removed) - new: tsgo --noEmit (alongside tsc fallback) - lefthook (and lefthook.yml) -> husky 9 with the standard scripts/ensure-husky.mjs self-heal pattern + lint-staged - new: gitleaks, actionlint, shellcheck as mise-managed binaries - TypeScript bumped target ES2020 -> ES2022 + lib ES2022 + DOM (for Error.cause and modern globals) Test migration (24 files): - Bulk-converted jest.* -> vi.*; jest.Mocked -> Mocked from vitest; jest.MockedFunction -> MockedFunction. - Added vitest imports to all *.test.ts files (and __mocks__/*.ts) that didn't have them. - src/index.ts: extracted runMain() as a named export and gated the module-level invocation behind NODE_ENV !== 'test'. The index-plugin-features test now calls runMain() directly instead of relying on jest's removed vi.isolateModules. - index-plugin-features.test.ts: moved hoisted refs (mockPlugin, mockLoadOrchestratorPlugin) into vi.hoisted() so vi.mock factories can reference them. Replaced arrow constructor mock for ImageTag with regular function() {...} (vitest 4 disallows arrows as ctors). Replaced require('./model') / require('@actions/core') inside test bodies with top-level imports. - model/orchestrator-plugin.test.ts: dropped jest's '{ virtual: true }' flag (vitest doesn't support it); replaced the 'mock factory throws' pattern with 'createPlugin throws' so vitest doesn't wrap the error message at the assertion site. - model/versioning.test.ts: stray jest.spyOn -> vi.spyOn; replaced mockImplementation() with no args (jest pattern) by mockResolvedValue('') / mockImplementation(() => undefined) where the source expects a string return. Workflow shell-quoting cleanup (actionlint): - All bare $GITHUB_STEP_SUMMARY / $GITHUB_OUTPUT / $GITHUB_ENV redirects quoted across 2 workflows (SC2086). - s3://$AWS_STACK_NAME / s3://$BUCKET_NAME -> s3://"$AWS_STACK_NAME" / s3://"$BUCKET_NAME". - 'for i in {1..N}; do ... done' loops where i isn't referenced in the body renamed to 'for _ in' (SC2034). - 'grep ... | wc -l' -> 'grep -c ...' (SC2126). - Multiple consecutive '>> $file' redirects in validate-community-plugins.yml summary block collapsed into a single block redirect (SC2129). - 'cat $file | python3 -c "..."' -> 'python3 -c "..." < $file' (SC2002). - http://${VAR}:port -> http://"${VAR}":port (SC2086). tsgo: kept tsc --noEmit as the default 'typecheck' because unity-builder publishes CommonJS for the GitHub Action consumer, which conflicts with tsgo's bundler/node16 moduleResolution requirement (per playbook trap #9). 'yarn typecheck:tsgo' is wired up for when consumers move to ESM. Caveats: 28 pre-existing oxlint warnings remain (mostly typescript/no-explicit-any across the build-parameter shapes and vitest/no-disabled-tests on 2 explicitly skipped scenarios). Per playbook trap #22 the lint script drops --deny-warnings. Verified locally: format clean, lint 0/28, typecheck clean, test 340/342 (2 pre-existing skipped), actionlint clean across all 12 workflows. * ci(unity-builder): fix Tests + Plugin Architecture Health on quality-tightening Three issues surfaced in CI after the jest -> vitest port: 1. **Obsolete snapshot blocks Tests job.** src/model/__snapshots__/versioning.test.ts.snap had two entries for the same 'throws for invalid strategy' assertion: one in the vitest format ('Versioning > determineBuildVersion > ...') and one in the legacy jest format without the '>'. vitest correctly regenerates the new one and flags the old one as obsolete; CI runs without --update so 'Test Files 1 failed' even though all 343 tests passed. Removed the obsolete entry. 2. **'Plugin Architecture Health' workflow still calls jest.** .github/workflows/validate-orchestrator.yml had two 'npx jest' steps (orchestrator-plugin unit tests + orchestrator-standalone tests). The unity-builder + orchestrator codebases are both on vitest now. Replaced both with 'yarn vitest run'. 3. **jest-fail-on-console + src/jest.setup.ts left over.** The earlier vitest port missed the jest-fail-on-console integration. yarn install in CI surfaced YN0002: doesn't provide @jest/globals (requested by jest-fail-on-console). Removed jest-fail-on-console + jest.setup.ts; added src/test/setup.ts with the equivalent vitest beforeEach spies (same as unity-test-runner). ---------
…i→PluginOptions rename (#837)
* fix: remove concurrency block from reusable workflow to prevent deadlock
When integrity-check.yml calls validate-orchestrator-integration.yml via
workflow_call, both workflows resolve github.workflow to the same name
("Integrity"), creating identical concurrency groups. GitHub detects this
as a deadlock and cancels the run.
Fix: remove concurrency from the reusable workflow entirely — the caller
already manages concurrency for the group.
* feat: add linux64RemoveExecutableExtension parameter (default: false)
Adds configurable control over the `.x86_64` file extension for
StandaloneLinux64 builds. Default is `false` (keep the extension),
matching Unity's native behavior.
Set `linux64RemoveExecutableExtension: true` to restore the
extensionless behavior from v4.
Rebased from kitlith's original PR #726. Default flipped for v5.
Closes #722
* chore: bump production dependencies (minor/patch)
- @actions/cache ^4.0.0 → ^4.1.0
- @actions/github ^6.0.0 → ^6.0.1
- commander ^9.0.0 → ^9.5.0
- nanoid ^3.3.1 → ^3.3.12
- reflect-metadata ^0.1.13 → ^0.2.2
- semver ^7.5.2 → ^7.7.4
- yaml ^2.2.2 → ^2.8.4
All minor/patch bumps. Major bumps (@actions/core 3.x, nanoid 5.x ESM)
deferred to a separate PR.
* chore: remove legacy CLI bootstrap and unused deps
Remove InitCliMode/RunCli, @CliFunction decorator, and
CliFunctionsRepository. The only registered CLI mode was `print-input`
which is unused — all real CLI functionality lives in the orchestrator
repo now.
This drops 3 dependencies:
- commander-ts (decorator-based CLI, needed reflect-metadata)
- reflect-metadata (peer dep of commander-ts)
- commander (only used for OptionValues type)
Cli.options, Cli.isCliMode, and Cli.query remain — the orchestrator
plugin sets these directly without commander.
* refactor: rename Cli to PluginOptions, remove cli directory
Cli class was a legacy name from when unity-builder had its own CLI.
Now it's just an options bridge for plugins — renamed to PluginOptions
with a backwards-compatible Cli alias for the orchestrator.
Moved from src/model/cli/cli.ts to src/model/plugin-options.ts.
* fix(ci): fix orchestrator integration test failures
Two issues:
1. jest → vitest: the repo migrated to vitest but the integration
workflow still called `npx jest`. Changed to `npx vitest run`.
2. Git checkout corruption: when the orchestrator branch matching the
PR doesn't exist, the first checkout fails leaving a corrupted .git
directory. The fallback step then hits `fatal: ambiguous argument
'HEAD'`. Fix: add `clean: true` to all fallback checkout steps so
they wipe the broken state before re-cloning.
* fix(ci): wipe .git before fallback checkout, fix remaining jest syntax
- Add `rm -rf .git` step before fallback checkout to clear corrupted
state when branch-matching checkout fails
- Fix unit test step: replace jest --testPathPattern with vitest
positional filters (same fix as orchestrator PR #18)
- Replace all --detectOpenHandles --forceExit --runInBand with
vitest --no-file-parallelism
* refactor: simplify plugin mode check
---------
…i→PluginOptions rename (#837)
* fix: remove concurrency block from reusable workflow to prevent deadlock
When integrity-check.yml calls validate-orchestrator-integration.yml via
workflow_call, both workflows resolve github.workflow to the same name
("Integrity"), creating identical concurrency groups. GitHub detects this
as a deadlock and cancels the run.
Fix: remove concurrency from the reusable workflow entirely — the caller
already manages concurrency for the group.
* feat: add linux64RemoveExecutableExtension parameter (default: false)
Adds configurable control over the `.x86_64` file extension for
StandaloneLinux64 builds. Default is `false` (keep the extension),
matching Unity's native behavior.
Set `linux64RemoveExecutableExtension: true` to restore the
extensionless behavior from v4.
Rebased from kitlith's original PR #726. Default flipped for v5.
Closes #722
* chore: bump production dependencies (minor/patch)
- @actions/cache ^4.0.0 → ^4.1.0
- @actions/github ^6.0.0 → ^6.0.1
- commander ^9.0.0 → ^9.5.0
- nanoid ^3.3.1 → ^3.3.12
- reflect-metadata ^0.1.13 → ^0.2.2
- semver ^7.5.2 → ^7.7.4
- yaml ^2.2.2 → ^2.8.4
All minor/patch bumps. Major bumps (@actions/core 3.x, nanoid 5.x ESM)
deferred to a separate PR.
* chore: remove legacy CLI bootstrap and unused deps
Remove InitCliMode/RunCli, @CliFunction decorator, and
CliFunctionsRepository. The only registered CLI mode was `print-input`
which is unused — all real CLI functionality lives in the orchestrator
repo now.
This drops 3 dependencies:
- commander-ts (decorator-based CLI, needed reflect-metadata)
- reflect-metadata (peer dep of commander-ts)
- commander (only used for OptionValues type)
Cli.options, Cli.isCliMode, and Cli.query remain — the orchestrator
plugin sets these directly without commander.
* refactor: rename Cli to PluginOptions, remove cli directory
Cli class was a legacy name from when unity-builder had its own CLI.
Now it's just an options bridge for plugins — renamed to PluginOptions
with a backwards-compatible Cli alias for the orchestrator.
Moved from src/model/cli/cli.ts to src/model/plugin-options.ts.
* fix(ci): fix orchestrator integration test failures
Two issues:
1. jest → vitest: the repo migrated to vitest but the integration
workflow still called `npx jest`. Changed to `npx vitest run`.
2. Git checkout corruption: when the orchestrator branch matching the
PR doesn't exist, the first checkout fails leaving a corrupted .git
directory. The fallback step then hits `fatal: ambiguous argument
'HEAD'`. Fix: add `clean: true` to all fallback checkout steps so
they wipe the broken state before re-cloning.
* fix(ci): wipe .git before fallback checkout, fix remaining jest syntax
- Add `rm -rf .git` step before fallback checkout to clear corrupted
state when branch-matching checkout fails
- Fix unit test step: replace jest --testPathPattern with vitest
positional filters (same fix as orchestrator PR #18)
- Replace all --detectOpenHandles --forceExit --runInBand with
vitest --no-file-parallelism
* refactor: simplify plugin mode check
---------
…i→PluginOptions rename (#837)
* fix: remove concurrency block from reusable workflow to prevent deadlock
When integrity-check.yml calls validate-orchestrator-integration.yml via
workflow_call, both workflows resolve github.workflow to the same name
("Integrity"), creating identical concurrency groups. GitHub detects this
as a deadlock and cancels the run.
Fix: remove concurrency from the reusable workflow entirely — the caller
already manages concurrency for the group.
* feat: add linux64RemoveExecutableExtension parameter (default: false)
Adds configurable control over the `.x86_64` file extension for
StandaloneLinux64 builds. Default is `false` (keep the extension),
matching Unity's native behavior.
Set `linux64RemoveExecutableExtension: true` to restore the
extensionless behavior from v4.
Rebased from kitlith's original PR #726. Default flipped for v5.
Closes #722
* chore: bump production dependencies (minor/patch)
- @actions/cache ^4.0.0 → ^4.1.0
- @actions/github ^6.0.0 → ^6.0.1
- commander ^9.0.0 → ^9.5.0
- nanoid ^3.3.1 → ^3.3.12
- reflect-metadata ^0.1.13 → ^0.2.2
- semver ^7.5.2 → ^7.7.4
- yaml ^2.2.2 → ^2.8.4
All minor/patch bumps. Major bumps (@actions/core 3.x, nanoid 5.x ESM)
deferred to a separate PR.
* chore: remove legacy CLI bootstrap and unused deps
Remove InitCliMode/RunCli, @CliFunction decorator, and
CliFunctionsRepository. The only registered CLI mode was `print-input`
which is unused — all real CLI functionality lives in the orchestrator
repo now.
This drops 3 dependencies:
- commander-ts (decorator-based CLI, needed reflect-metadata)
- reflect-metadata (peer dep of commander-ts)
- commander (only used for OptionValues type)
Cli.options, Cli.isCliMode, and Cli.query remain — the orchestrator
plugin sets these directly without commander.
* refactor: rename Cli to PluginOptions, remove cli directory
Cli class was a legacy name from when unity-builder had its own CLI.
Now it's just an options bridge for plugins — renamed to PluginOptions
with a backwards-compatible Cli alias for the orchestrator.
Moved from src/model/cli/cli.ts to src/model/plugin-options.ts.
* fix(ci): fix orchestrator integration test failures
Two issues:
1. jest → vitest: the repo migrated to vitest but the integration
workflow still called `npx jest`. Changed to `npx vitest run`.
2. Git checkout corruption: when the orchestrator branch matching the
PR doesn't exist, the first checkout fails leaving a corrupted .git
directory. The fallback step then hits `fatal: ambiguous argument
'HEAD'`. Fix: add `clean: true` to all fallback checkout steps so
they wipe the broken state before re-cloning.
* fix(ci): wipe .git before fallback checkout, fix remaining jest syntax
- Add `rm -rf .git` step before fallback checkout to clear corrupted
state when branch-matching checkout fails
- Fix unit test step: replace jest --testPathPattern with vitest
positional filters (same fix as orchestrator PR #18)
- Replace all --detectOpenHandles --forceExit --runInBand with
vitest --no-file-parallelism
* refactor: simplify plugin mode check
---------
…i→PluginOptions rename (#837)
* fix: remove concurrency block from reusable workflow to prevent deadlock
When integrity-check.yml calls validate-orchestrator-integration.yml via
workflow_call, both workflows resolve github.workflow to the same name
("Integrity"), creating identical concurrency groups. GitHub detects this
as a deadlock and cancels the run.
Fix: remove concurrency from the reusable workflow entirely — the caller
already manages concurrency for the group.
* feat: add linux64RemoveExecutableExtension parameter (default: false)
Adds configurable control over the `.x86_64` file extension for
StandaloneLinux64 builds. Default is `false` (keep the extension),
matching Unity's native behavior.
Set `linux64RemoveExecutableExtension: true` to restore the
extensionless behavior from v4.
Rebased from kitlith's original PR #726. Default flipped for v5.
Closes #722
* chore: bump production dependencies (minor/patch)
- @actions/cache ^4.0.0 → ^4.1.0
- @actions/github ^6.0.0 → ^6.0.1
- commander ^9.0.0 → ^9.5.0
- nanoid ^3.3.1 → ^3.3.12
- reflect-metadata ^0.1.13 → ^0.2.2
- semver ^7.5.2 → ^7.7.4
- yaml ^2.2.2 → ^2.8.4
All minor/patch bumps. Major bumps (@actions/core 3.x, nanoid 5.x ESM)
deferred to a separate PR.
* chore: remove legacy CLI bootstrap and unused deps
Remove InitCliMode/RunCli, @CliFunction decorator, and
CliFunctionsRepository. The only registered CLI mode was `print-input`
which is unused — all real CLI functionality lives in the orchestrator
repo now.
This drops 3 dependencies:
- commander-ts (decorator-based CLI, needed reflect-metadata)
- reflect-metadata (peer dep of commander-ts)
- commander (only used for OptionValues type)
Cli.options, Cli.isCliMode, and Cli.query remain — the orchestrator
plugin sets these directly without commander.
* refactor: rename Cli to PluginOptions, remove cli directory
Cli class was a legacy name from when unity-builder had its own CLI.
Now it's just an options bridge for plugins — renamed to PluginOptions
with a backwards-compatible Cli alias for the orchestrator.
Moved from src/model/cli/cli.ts to src/model/plugin-options.ts.
* fix(ci): fix orchestrator integration test failures
Two issues:
1. jest → vitest: the repo migrated to vitest but the integration
workflow still called `npx jest`. Changed to `npx vitest run`.
2. Git checkout corruption: when the orchestrator branch matching the
PR doesn't exist, the first checkout fails leaving a corrupted .git
directory. The fallback step then hits `fatal: ambiguous argument
'HEAD'`. Fix: add `clean: true` to all fallback checkout steps so
they wipe the broken state before re-cloning.
* fix(ci): wipe .git before fallback checkout, fix remaining jest syntax
- Add `rm -rf .git` step before fallback checkout to clear corrupted
state when branch-matching checkout fails
- Fix unit test step: replace jest --testPathPattern with vitest
positional filters (same fix as orchestrator PR #18)
- Replace all --detectOpenHandles --forceExit --runInBand with
vitest --no-file-parallelism
* refactor: simplify plugin mode check
---------
…i→PluginOptions rename (#837)
* fix: remove concurrency block from reusable workflow to prevent deadlock
When integrity-check.yml calls validate-orchestrator-integration.yml via
workflow_call, both workflows resolve github.workflow to the same name
("Integrity"), creating identical concurrency groups. GitHub detects this
as a deadlock and cancels the run.
Fix: remove concurrency from the reusable workflow entirely — the caller
already manages concurrency for the group.
* feat: add linux64RemoveExecutableExtension parameter (default: false)
Adds configurable control over the `.x86_64` file extension for
StandaloneLinux64 builds. Default is `false` (keep the extension),
matching Unity's native behavior.
Set `linux64RemoveExecutableExtension: true` to restore the
extensionless behavior from v4.
Rebased from kitlith's original PR #726. Default flipped for v5.
Closes #722
* chore: bump production dependencies (minor/patch)
- @actions/cache ^4.0.0 → ^4.1.0
- @actions/github ^6.0.0 → ^6.0.1
- commander ^9.0.0 → ^9.5.0
- nanoid ^3.3.1 → ^3.3.12
- reflect-metadata ^0.1.13 → ^0.2.2
- semver ^7.5.2 → ^7.7.4
- yaml ^2.2.2 → ^2.8.4
All minor/patch bumps. Major bumps (@actions/core 3.x, nanoid 5.x ESM)
deferred to a separate PR.
* chore: remove legacy CLI bootstrap and unused deps
Remove InitCliMode/RunCli, @CliFunction decorator, and
CliFunctionsRepository. The only registered CLI mode was `print-input`
which is unused — all real CLI functionality lives in the orchestrator
repo now.
This drops 3 dependencies:
- commander-ts (decorator-based CLI, needed reflect-metadata)
- reflect-metadata (peer dep of commander-ts)
- commander (only used for OptionValues type)
Cli.options, Cli.isCliMode, and Cli.query remain — the orchestrator
plugin sets these directly without commander.
* refactor: rename Cli to PluginOptions, remove cli directory
Cli class was a legacy name from when unity-builder had its own CLI.
Now it's just an options bridge for plugins — renamed to PluginOptions
with a backwards-compatible Cli alias for the orchestrator.
Moved from src/model/cli/cli.ts to src/model/plugin-options.ts.
* fix(ci): fix orchestrator integration test failures
Two issues:
1. jest → vitest: the repo migrated to vitest but the integration
workflow still called `npx jest`. Changed to `npx vitest run`.
2. Git checkout corruption: when the orchestrator branch matching the
PR doesn't exist, the first checkout fails leaving a corrupted .git
directory. The fallback step then hits `fatal: ambiguous argument
'HEAD'`. Fix: add `clean: true` to all fallback checkout steps so
they wipe the broken state before re-cloning.
* fix(ci): wipe .git before fallback checkout, fix remaining jest syntax
- Add `rm -rf .git` step before fallback checkout to clear corrupted
state when branch-matching checkout fails
- Fix unit test step: replace jest --testPathPattern with vitest
positional filters (same fix as orchestrator PR #18)
- Replace all --detectOpenHandles --forceExit --runInBand with
vitest --no-file-parallelism
* refactor: simplify plugin mode check
---------
…i→PluginOptions rename (#837)
* fix: remove concurrency block from reusable workflow to prevent deadlock
When integrity-check.yml calls validate-orchestrator-integration.yml via
workflow_call, both workflows resolve github.workflow to the same name
("Integrity"), creating identical concurrency groups. GitHub detects this
as a deadlock and cancels the run.
Fix: remove concurrency from the reusable workflow entirely — the caller
already manages concurrency for the group.
* feat: add linux64RemoveExecutableExtension parameter (default: false)
Adds configurable control over the `.x86_64` file extension for
StandaloneLinux64 builds. Default is `false` (keep the extension),
matching Unity's native behavior.
Set `linux64RemoveExecutableExtension: true` to restore the
extensionless behavior from v4.
Rebased from kitlith's original PR #726. Default flipped for v5.
Closes #722
* chore: bump production dependencies (minor/patch)
- @actions/cache ^4.0.0 → ^4.1.0
- @actions/github ^6.0.0 → ^6.0.1
- commander ^9.0.0 → ^9.5.0
- nanoid ^3.3.1 → ^3.3.12
- reflect-metadata ^0.1.13 → ^0.2.2
- semver ^7.5.2 → ^7.7.4
- yaml ^2.2.2 → ^2.8.4
All minor/patch bumps. Major bumps (@actions/core 3.x, nanoid 5.x ESM)
deferred to a separate PR.
* chore: remove legacy CLI bootstrap and unused deps
Remove InitCliMode/RunCli, @CliFunction decorator, and
CliFunctionsRepository. The only registered CLI mode was `print-input`
which is unused — all real CLI functionality lives in the orchestrator
repo now.
This drops 3 dependencies:
- commander-ts (decorator-based CLI, needed reflect-metadata)
- reflect-metadata (peer dep of commander-ts)
- commander (only used for OptionValues type)
Cli.options, Cli.isCliMode, and Cli.query remain — the orchestrator
plugin sets these directly without commander.
* refactor: rename Cli to PluginOptions, remove cli directory
Cli class was a legacy name from when unity-builder had its own CLI.
Now it's just an options bridge for plugins — renamed to PluginOptions
with a backwards-compatible Cli alias for the orchestrator.
Moved from src/model/cli/cli.ts to src/model/plugin-options.ts.
* fix(ci): fix orchestrator integration test failures
Two issues:
1. jest → vitest: the repo migrated to vitest but the integration
workflow still called `npx jest`. Changed to `npx vitest run`.
2. Git checkout corruption: when the orchestrator branch matching the
PR doesn't exist, the first checkout fails leaving a corrupted .git
directory. The fallback step then hits `fatal: ambiguous argument
'HEAD'`. Fix: add `clean: true` to all fallback checkout steps so
they wipe the broken state before re-cloning.
* fix(ci): wipe .git before fallback checkout, fix remaining jest syntax
- Add `rm -rf .git` step before fallback checkout to clear corrupted
state when branch-matching checkout fails
- Fix unit test step: replace jest --testPathPattern with vitest
positional filters (same fix as orchestrator PR #18)
- Replace all --detectOpenHandles --forceExit --runInBand with
vitest --no-file-parallelism
* refactor: simplify plugin mode check
---------
45aefb4 to
1dd3c50
Compare
🔍 Cherry-Pick Verification Report📦 Upstream Changes: 📋 File-by-File Analysis:
|
🔍 Cherry-Pick Verification Report📦 Upstream Changes: 📋 File-by-File Analysis:
|
🔍 Cherry-Pick Verification Report📦 Upstream Changes: 📋 File-by-File Analysis:
|
🔍 Cherry-Pick Verification Report📦 Upstream Changes: 📋 File-by-File Analysis:
|
🔍 Cherry-Pick Verification Report📦 Upstream Changes: 📋 File-by-File Analysis:
|
🔍 Cherry-Pick Verification Report📦 Upstream Changes: 📋 File-by-File Analysis:
|
🔍 Cherry-Pick Verification Report📦 Upstream Changes: 📋 File-by-File Analysis:
|
🔍 Cherry-Pick Verification Report📦 Upstream Changes: 📋 File-by-File Analysis:
|
🔍 Cherry-Pick Verification Report📦 Upstream Changes: 📋 File-by-File Analysis:
|
Cherry-picked changes from upstream.