mirror of
https://github.com/game-ci/unity-builder.git
synced 2026-05-31 13:56:13 -07:00
Generalize unity-builder plugin contract (#832)
* refactor: generalize unity-builder plugin contract * test: preserve orchestrator plugin compatibility target * refactor: rename build plugin to plugin
This commit is contained in:
438
dist/index.js
generated
vendored
438
dist/index.js
generated
vendored
@@ -38,7 +38,7 @@ const model_1 = __nccwpck_require__(41359);
|
||||
const cli_1 = __nccwpck_require__(55651);
|
||||
const mac_builder_1 = __importDefault(__nccwpck_require__(39364));
|
||||
const platform_setup_1 = __importDefault(__nccwpck_require__(64423));
|
||||
const orchestrator_plugin_1 = __nccwpck_require__(2075);
|
||||
const plugin_1 = __nccwpck_require__(67270);
|
||||
async function runMain() {
|
||||
try {
|
||||
if (cli_1.Cli.InitCliMode()) {
|
||||
@@ -50,8 +50,8 @@ async function runMain() {
|
||||
const { workspace, actionFolder } = model_1.Action;
|
||||
const buildParameters = await model_1.BuildParameters.create();
|
||||
const baseImage = new model_1.ImageTag(buildParameters);
|
||||
// Load orchestrator plugin (optional — only needed for remote builds and plugin features)
|
||||
const plugin = await (0, orchestrator_plugin_1.loadOrchestratorPlugin)();
|
||||
// Load optional plugin. The default implementation is @game-ci/orchestrator.
|
||||
const plugin = await (0, plugin_1.loadPlugin)();
|
||||
await plugin?.initialize(buildParameters, workspace);
|
||||
let exitCode = -1;
|
||||
if (plugin?.canHandleBuild()) {
|
||||
@@ -1522,72 +1522,6 @@ class MacBuilder {
|
||||
exports["default"] = MacBuilder;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 2075:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.loadOrchestratorPlugin = void 0;
|
||||
const core = __importStar(__nccwpck_require__(42186));
|
||||
/**
|
||||
* Attempt to load the orchestrator plugin.
|
||||
* Returns undefined if @game-ci/orchestrator is not installed.
|
||||
*/
|
||||
async function loadOrchestratorPlugin() {
|
||||
try {
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
const orchestratorModule = await Promise.resolve().then(() => __importStar(__nccwpck_require__(70776)));
|
||||
if (typeof orchestratorModule.createPlugin !== 'function') {
|
||||
core.warning('Orchestrator package found but does not export createPlugin(). ' +
|
||||
'Update @game-ci/orchestrator to the latest version.');
|
||||
return;
|
||||
}
|
||||
return orchestratorModule.createPlugin();
|
||||
}
|
||||
catch (error) {
|
||||
if (!isModuleNotFoundError(error)) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.loadOrchestratorPlugin = loadOrchestratorPlugin;
|
||||
function isModuleNotFoundError(error) {
|
||||
if (error && typeof error === 'object' && 'code' in error) {
|
||||
const code = error.code;
|
||||
if (code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return typeof error?.message === 'string' && /cannot find module/i.test(error.message);
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 85487:
|
||||
@@ -2092,6 +2026,76 @@ class Platform {
|
||||
exports["default"] = Platform;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 67270:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.loadPlugin = void 0;
|
||||
const core = __importStar(__nccwpck_require__(42186));
|
||||
const DEFAULT_PLUGIN_MODULE = '@game-ci/orchestrator';
|
||||
/**
|
||||
* Attempt to load the default optional plugin.
|
||||
*
|
||||
* Today the default implementation is @game-ci/orchestrator. The loader is
|
||||
* intentionally named after the generic plugin contract so additional plugin
|
||||
* implementations can be added without making orchestrator part of the core
|
||||
* abstraction.
|
||||
*/
|
||||
async function loadPlugin(moduleName = DEFAULT_PLUGIN_MODULE) {
|
||||
try {
|
||||
const pluginModule = await Promise.resolve().then(() => __importStar(require(/* webpackIgnore: true */ moduleName)));
|
||||
if (typeof pluginModule.createPlugin !== 'function') {
|
||||
core.warning(`Plugin package "${moduleName}" found but does not export createPlugin(). ` +
|
||||
'Update the plugin package to the latest version.');
|
||||
return;
|
||||
}
|
||||
return pluginModule.createPlugin();
|
||||
}
|
||||
catch (error) {
|
||||
if (!isModuleNotFoundError(error)) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.loadPlugin = loadPlugin;
|
||||
function isModuleNotFoundError(error) {
|
||||
if (error && typeof error === 'object' && 'code' in error) {
|
||||
const code = error.code;
|
||||
if (code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return typeof error?.message === 'string' && /cannot find module/i.test(error.message);
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 88666:
|
||||
@@ -76007,14 +76011,6 @@ module.exports = {
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 70776:
|
||||
/***/ ((module) => {
|
||||
|
||||
module.exports = eval("require")("@game-ci/orchestrator");
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 22877:
|
||||
@@ -91074,6 +91070,24 @@ exports.StorageContextClient = StorageContextClient;
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 39241:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.KnownEncryptionAlgorithmType = void 0;
|
||||
/** Known values of {@link EncryptionAlgorithmType} that the service accepts. */
|
||||
var KnownEncryptionAlgorithmType;
|
||||
(function (KnownEncryptionAlgorithmType) {
|
||||
KnownEncryptionAlgorithmType["AES256"] = "AES256";
|
||||
})(KnownEncryptionAlgorithmType || (exports.KnownEncryptionAlgorithmType = KnownEncryptionAlgorithmType = {}));
|
||||
//# sourceMappingURL=generatedModels.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 57955:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
|
||||
@@ -101400,6 +101414,132 @@ exports.listType = {
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 24763:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
//# sourceMappingURL=appendBlob.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 57427:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
//# sourceMappingURL=blob.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 56945:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
//# sourceMappingURL=blockBlob.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 43634:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
//# sourceMappingURL=container.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 68529:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
const tslib_1 = __nccwpck_require__(4351);
|
||||
tslib_1.__exportStar(__nccwpck_require__(75650), exports);
|
||||
tslib_1.__exportStar(__nccwpck_require__(43634), exports);
|
||||
tslib_1.__exportStar(__nccwpck_require__(57427), exports);
|
||||
tslib_1.__exportStar(__nccwpck_require__(76425), exports);
|
||||
tslib_1.__exportStar(__nccwpck_require__(24763), exports);
|
||||
tslib_1.__exportStar(__nccwpck_require__(56945), exports);
|
||||
//# sourceMappingURL=index.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 76425:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
//# sourceMappingURL=pageBlob.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 75650:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
//# sourceMappingURL=service.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 80313:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
|
||||
@@ -104615,132 +104755,6 @@ const filterBlobsOperationSpec = {
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 24763:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
//# sourceMappingURL=appendBlob.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 57427:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
//# sourceMappingURL=blob.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 56945:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
//# sourceMappingURL=blockBlob.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 43634:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
//# sourceMappingURL=container.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 68529:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
const tslib_1 = __nccwpck_require__(4351);
|
||||
tslib_1.__exportStar(__nccwpck_require__(75650), exports);
|
||||
tslib_1.__exportStar(__nccwpck_require__(43634), exports);
|
||||
tslib_1.__exportStar(__nccwpck_require__(57427), exports);
|
||||
tslib_1.__exportStar(__nccwpck_require__(76425), exports);
|
||||
tslib_1.__exportStar(__nccwpck_require__(24763), exports);
|
||||
tslib_1.__exportStar(__nccwpck_require__(56945), exports);
|
||||
//# sourceMappingURL=index.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 76425:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
//# sourceMappingURL=pageBlob.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 75650:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
//# sourceMappingURL=service.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 50166:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
|
||||
@@ -104814,24 +104828,6 @@ exports.StorageClient = StorageClient;
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 39241:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.KnownEncryptionAlgorithmType = void 0;
|
||||
/** Known values of {@link EncryptionAlgorithmType} that the service accepts. */
|
||||
var KnownEncryptionAlgorithmType;
|
||||
(function (KnownEncryptionAlgorithmType) {
|
||||
KnownEncryptionAlgorithmType["AES256"] = "AES256";
|
||||
})(KnownEncryptionAlgorithmType || (exports.KnownEncryptionAlgorithmType = KnownEncryptionAlgorithmType = {}));
|
||||
//# sourceMappingURL=generatedModels.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 37168:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
|
||||
|
||||
2
dist/index.js.map
generated
vendored
2
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -24,10 +24,10 @@ const mockPlugin = {
|
||||
handlePostBuild: jest.fn().mockResolvedValue(undefined),
|
||||
};
|
||||
|
||||
const mockLoadOrchestratorPlugin = jest.fn().mockResolvedValue(mockPlugin);
|
||||
const mockLoadPlugin = jest.fn().mockResolvedValue(mockPlugin);
|
||||
|
||||
jest.mock('./model/orchestrator-plugin', () => ({
|
||||
loadOrchestratorPlugin: mockLoadOrchestratorPlugin,
|
||||
jest.mock('./model/plugin', () => ({
|
||||
loadPlugin: mockLoadPlugin,
|
||||
}));
|
||||
|
||||
jest.mock('@actions/core');
|
||||
@@ -119,7 +119,7 @@ describe('index.ts plugin lifecycle wiring', () => {
|
||||
// Reset plugin to default behavior
|
||||
mockPlugin.canHandleBuild.mockReturnValue(false);
|
||||
mockPlugin.handleBuild.mockResolvedValue({ exitCode: 0 });
|
||||
mockLoadOrchestratorPlugin.mockResolvedValue(mockPlugin);
|
||||
mockLoadPlugin.mockResolvedValue(mockPlugin);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -226,7 +226,7 @@ describe('index.ts plugin lifecycle wiring', () => {
|
||||
describe('no plugin installed', () => {
|
||||
it('should build locally without errors when providerStrategy is local', async () => {
|
||||
const { Docker } = require('./model');
|
||||
mockLoadOrchestratorPlugin.mockResolvedValue(undefined);
|
||||
mockLoadPlugin.mockResolvedValue(undefined);
|
||||
|
||||
await runIndex({ providerStrategy: 'local' });
|
||||
|
||||
@@ -235,7 +235,7 @@ describe('index.ts plugin lifecycle wiring', () => {
|
||||
|
||||
it('should error when providerStrategy is non-local and no plugin', async () => {
|
||||
const core = require('@actions/core');
|
||||
mockLoadOrchestratorPlugin.mockResolvedValue(undefined);
|
||||
mockLoadPlugin.mockResolvedValue(undefined);
|
||||
|
||||
await runIndex({ providerStrategy: 'aws' });
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Action, BuildParameters, Cache, Docker, ImageTag, Output } from './mode
|
||||
import { Cli } from './model/cli/cli';
|
||||
import MacBuilder from './model/mac-builder';
|
||||
import PlatformSetup from './model/platform-setup';
|
||||
import { loadOrchestratorPlugin, OrchestratorPlugin } from './model/orchestrator-plugin';
|
||||
import { Plugin, loadPlugin } from './model/plugin';
|
||||
|
||||
async function runMain() {
|
||||
try {
|
||||
@@ -19,8 +19,8 @@ async function runMain() {
|
||||
const buildParameters = await BuildParameters.create();
|
||||
const baseImage = new ImageTag(buildParameters);
|
||||
|
||||
// Load orchestrator plugin (optional — only needed for remote builds and plugin features)
|
||||
const plugin = await loadOrchestratorPlugin();
|
||||
// Load optional plugin. The default implementation is @game-ci/orchestrator.
|
||||
const plugin = await loadPlugin();
|
||||
await plugin?.initialize(buildParameters, workspace);
|
||||
|
||||
let exitCode = -1;
|
||||
@@ -62,7 +62,7 @@ async function runLocalBuild(
|
||||
baseImage: ImageTag,
|
||||
workspace: string,
|
||||
actionFolder: string,
|
||||
plugin?: OrchestratorPlugin,
|
||||
plugin?: Plugin,
|
||||
): Promise<number> {
|
||||
await plugin?.beforeLocalBuild(workspace);
|
||||
|
||||
|
||||
@@ -1,129 +1,15 @@
|
||||
/**
|
||||
* Tests for the orchestrator plugin loader (orchestrator-plugin.ts).
|
||||
* Compatibility tests for the legacy orchestrator-plugin module name.
|
||||
*
|
||||
* The plugin loader dynamically imports @game-ci/orchestrator and calls
|
||||
* createPlugin(). Two scenarios:
|
||||
*
|
||||
* 1. Package NOT installed — loadOrchestratorPlugin() returns undefined.
|
||||
* 2. Package IS installed — returns the plugin from createPlugin().
|
||||
* CI targets this file pattern directly, and consumers may still import this
|
||||
* module while migrating to the generic plugin API.
|
||||
*/
|
||||
|
||||
const mockWarning = jest.fn();
|
||||
const mockInfo = jest.fn();
|
||||
jest.mock('@actions/core', () => ({
|
||||
warning: mockWarning,
|
||||
info: mockInfo,
|
||||
}));
|
||||
describe('orchestrator-plugin compatibility exports', () => {
|
||||
it('keeps loadOrchestratorPlugin as an alias for loadPlugin', async () => {
|
||||
const plugin = await import('./plugin');
|
||||
const compatibility = await import('./orchestrator-plugin');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
mockWarning.mockClear();
|
||||
mockInfo.mockClear();
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Part 1: Package NOT installed
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('orchestrator-plugin (package not installed)', () => {
|
||||
it('loadOrchestratorPlugin() returns undefined', async () => {
|
||||
const { loadOrchestratorPlugin } = await import('./orchestrator-plugin');
|
||||
|
||||
const result = await loadOrchestratorPlugin();
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Part 2: Package IS installed (mocked)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('orchestrator-plugin (package installed)', () => {
|
||||
const fakePlugin = {
|
||||
initialize: jest.fn(),
|
||||
canHandleBuild: jest.fn().mockReturnValue(false),
|
||||
handleBuild: jest.fn().mockResolvedValue({ exitCode: 0 }),
|
||||
beforeLocalBuild: jest.fn(),
|
||||
afterLocalBuild: jest.fn(),
|
||||
handlePostBuild: jest.fn(),
|
||||
};
|
||||
|
||||
const mockCreatePlugin = jest.fn().mockReturnValue(fakePlugin);
|
||||
|
||||
function installOrchestratorMock(overrides: Record<string, unknown> = {}) {
|
||||
jest.doMock(
|
||||
'@game-ci/orchestrator',
|
||||
() => ({
|
||||
createPlugin: mockCreatePlugin,
|
||||
...overrides,
|
||||
}),
|
||||
{ virtual: true },
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
mockCreatePlugin.mockClear();
|
||||
fakePlugin.initialize.mockClear();
|
||||
fakePlugin.canHandleBuild.mockClear();
|
||||
fakePlugin.handleBuild.mockClear();
|
||||
fakePlugin.beforeLocalBuild.mockClear();
|
||||
fakePlugin.afterLocalBuild.mockClear();
|
||||
fakePlugin.handlePostBuild.mockClear();
|
||||
});
|
||||
|
||||
it('returns the plugin from createPlugin()', async () => {
|
||||
installOrchestratorMock();
|
||||
const { loadOrchestratorPlugin } = await import('./orchestrator-plugin');
|
||||
|
||||
const plugin = await loadOrchestratorPlugin();
|
||||
|
||||
expect(plugin).toBeDefined();
|
||||
expect(mockCreatePlugin).toHaveBeenCalledTimes(1);
|
||||
expect(plugin).toBe(fakePlugin);
|
||||
});
|
||||
|
||||
it('returns the plugin with all lifecycle methods', async () => {
|
||||
installOrchestratorMock();
|
||||
const { loadOrchestratorPlugin } = await import('./orchestrator-plugin');
|
||||
|
||||
const plugin = await loadOrchestratorPlugin();
|
||||
|
||||
expect(typeof plugin!.initialize).toBe('function');
|
||||
expect(typeof plugin!.canHandleBuild).toBe('function');
|
||||
expect(typeof plugin!.handleBuild).toBe('function');
|
||||
expect(typeof plugin!.beforeLocalBuild).toBe('function');
|
||||
expect(typeof plugin!.afterLocalBuild).toBe('function');
|
||||
expect(typeof plugin!.handlePostBuild).toBe('function');
|
||||
});
|
||||
|
||||
it('returns undefined and warns when createPlugin is not a function', async () => {
|
||||
installOrchestratorMock({ createPlugin: undefined });
|
||||
const { loadOrchestratorPlugin } = await import('./orchestrator-plugin');
|
||||
|
||||
const plugin = await loadOrchestratorPlugin();
|
||||
|
||||
expect(plugin).toBeUndefined();
|
||||
expect(mockWarning).toHaveBeenCalledWith(expect.stringContaining('does not export createPlugin'));
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Error handling
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
describe('error handling', () => {
|
||||
it('propagates non-MODULE_NOT_FOUND errors', async () => {
|
||||
const importError = new Error('Syntax error in module');
|
||||
jest.doMock(
|
||||
'@game-ci/orchestrator',
|
||||
() => {
|
||||
throw importError;
|
||||
},
|
||||
{ virtual: true },
|
||||
);
|
||||
const { loadOrchestratorPlugin } = await import('./orchestrator-plugin');
|
||||
|
||||
await expect(loadOrchestratorPlugin()).rejects.toThrow('Syntax error in module');
|
||||
});
|
||||
expect(compatibility.loadOrchestratorPlugin).toBe(plugin.loadPlugin);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,73 +1,2 @@
|
||||
import * as core from '@actions/core';
|
||||
|
||||
/**
|
||||
* Lifecycle interface for the orchestrator plugin.
|
||||
*
|
||||
* The orchestrator reads its own configuration from environment variables
|
||||
* and GitHub Actions inputs. Unity-builder only calls these lifecycle hooks
|
||||
* at the appropriate times — it never needs to know individual plugin params.
|
||||
*/
|
||||
export interface OrchestratorPlugin {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
initialize(coreParameters: Record<string, any>, workspace: string): Promise<void>;
|
||||
|
||||
/** Whether the plugin wants to handle the entire build (remote, hot runner, test workflow). */
|
||||
canHandleBuild(): boolean;
|
||||
|
||||
/**
|
||||
* Execute the build when canHandleBuild() returns true.
|
||||
* If the plugin needs to fall back to a local build (e.g. hot runner failure),
|
||||
* it returns { exitCode: -1, fallbackToLocal: true }.
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
handleBuild(baseImage: string): Promise<{ exitCode: number; fallbackToLocal?: boolean }>;
|
||||
|
||||
/** Pre-build hook for local builds (cache restore, git hooks, sync, etc.). */
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
beforeLocalBuild(workspace: string): Promise<void>;
|
||||
|
||||
/** Post-build hook for local builds (cache save, workspace save, etc.). */
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
afterLocalBuild(workspace: string, exitCode: number): Promise<void>;
|
||||
|
||||
/** Post-build hook for all build types (archiving, artifacts, etc.). */
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
handlePostBuild(exitCode: number): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to load the orchestrator plugin.
|
||||
* Returns undefined if @game-ci/orchestrator is not installed.
|
||||
*/
|
||||
export async function loadOrchestratorPlugin(): Promise<OrchestratorPlugin | undefined> {
|
||||
try {
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
const orchestratorModule = await import('@game-ci/orchestrator');
|
||||
|
||||
if (typeof orchestratorModule.createPlugin !== 'function') {
|
||||
core.warning(
|
||||
'Orchestrator package found but does not export createPlugin(). ' +
|
||||
'Update @game-ci/orchestrator to the latest version.',
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return orchestratorModule.createPlugin();
|
||||
} catch (error) {
|
||||
if (!isModuleNotFoundError(error)) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isModuleNotFoundError(error: unknown): boolean {
|
||||
if (error && typeof error === 'object' && 'code' in error) {
|
||||
const code = (error as { code: string }).code;
|
||||
if (code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return typeof (error as Error)?.message === 'string' && /cannot find module/i.test((error as Error).message);
|
||||
}
|
||||
export { loadPlugin as loadOrchestratorPlugin } from './plugin';
|
||||
export type { Plugin as OrchestratorPlugin } from './plugin';
|
||||
|
||||
113
src/model/plugin.test.ts
Normal file
113
src/model/plugin.test.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Tests for the generic plugin loader (plugin.ts).
|
||||
*
|
||||
* The default plugin implementation is currently @game-ci/orchestrator, but
|
||||
* unity-builder depends on the generic Plugin lifecycle rather than an
|
||||
* orchestrator-specific type.
|
||||
*/
|
||||
|
||||
const mockWarning = jest.fn();
|
||||
const mockInfo = jest.fn();
|
||||
jest.mock('@actions/core', () => ({
|
||||
warning: mockWarning,
|
||||
info: mockInfo,
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
mockWarning.mockClear();
|
||||
mockInfo.mockClear();
|
||||
});
|
||||
|
||||
describe('plugin (default package not installed)', () => {
|
||||
it('loadPlugin() returns undefined', async () => {
|
||||
const { loadPlugin } = await import('./plugin');
|
||||
|
||||
const result = await loadPlugin();
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('plugin (default package installed)', () => {
|
||||
const fakePlugin = {
|
||||
initialize: jest.fn(),
|
||||
canHandleBuild: jest.fn().mockReturnValue(false),
|
||||
handleBuild: jest.fn().mockResolvedValue({ exitCode: 0 }),
|
||||
beforeLocalBuild: jest.fn(),
|
||||
afterLocalBuild: jest.fn(),
|
||||
handlePostBuild: jest.fn(),
|
||||
};
|
||||
|
||||
const mockCreatePlugin = jest.fn().mockReturnValue(fakePlugin);
|
||||
|
||||
function installDefaultPluginMock(overrides: Record<string, unknown> = {}) {
|
||||
jest.doMock(
|
||||
'@game-ci/orchestrator',
|
||||
() => ({
|
||||
createPlugin: mockCreatePlugin,
|
||||
...overrides,
|
||||
}),
|
||||
{ virtual: true },
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
mockCreatePlugin.mockClear();
|
||||
fakePlugin.initialize.mockClear();
|
||||
fakePlugin.canHandleBuild.mockClear();
|
||||
fakePlugin.handleBuild.mockClear();
|
||||
fakePlugin.beforeLocalBuild.mockClear();
|
||||
fakePlugin.afterLocalBuild.mockClear();
|
||||
fakePlugin.handlePostBuild.mockClear();
|
||||
});
|
||||
|
||||
it('returns the plugin from createPlugin()', async () => {
|
||||
installDefaultPluginMock();
|
||||
const { loadPlugin } = await import('./plugin');
|
||||
|
||||
const plugin = await loadPlugin();
|
||||
|
||||
expect(plugin).toBeDefined();
|
||||
expect(mockCreatePlugin).toHaveBeenCalledTimes(1);
|
||||
expect(plugin).toBe(fakePlugin);
|
||||
});
|
||||
|
||||
it('returns a plugin with all lifecycle methods', async () => {
|
||||
installDefaultPluginMock();
|
||||
const { loadPlugin } = await import('./plugin');
|
||||
|
||||
const plugin = await loadPlugin();
|
||||
|
||||
expect(typeof plugin!.initialize).toBe('function');
|
||||
expect(typeof plugin!.canHandleBuild).toBe('function');
|
||||
expect(typeof plugin!.handleBuild).toBe('function');
|
||||
expect(typeof plugin!.beforeLocalBuild).toBe('function');
|
||||
expect(typeof plugin!.afterLocalBuild).toBe('function');
|
||||
expect(typeof plugin!.handlePostBuild).toBe('function');
|
||||
});
|
||||
|
||||
it('returns undefined and warns when createPlugin is not a function', async () => {
|
||||
installDefaultPluginMock({ createPlugin: undefined });
|
||||
const { loadPlugin } = await import('./plugin');
|
||||
|
||||
const plugin = await loadPlugin();
|
||||
|
||||
expect(plugin).toBeUndefined();
|
||||
expect(mockWarning).toHaveBeenCalledWith(expect.stringContaining('does not export createPlugin'));
|
||||
});
|
||||
|
||||
it('propagates non-MODULE_NOT_FOUND errors', async () => {
|
||||
const importError = new Error('Syntax error in module');
|
||||
jest.doMock(
|
||||
'@game-ci/orchestrator',
|
||||
() => {
|
||||
throw importError;
|
||||
},
|
||||
{ virtual: true },
|
||||
);
|
||||
const { loadPlugin } = await import('./plugin');
|
||||
|
||||
await expect(loadPlugin()).rejects.toThrow('Syntax error in module');
|
||||
});
|
||||
});
|
||||
78
src/model/plugin.ts
Normal file
78
src/model/plugin.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import * as core from '@actions/core';
|
||||
|
||||
const DEFAULT_PLUGIN_MODULE = '@game-ci/orchestrator';
|
||||
|
||||
/**
|
||||
* Generic lifecycle contract for optional unity-builder plugins.
|
||||
*
|
||||
* Plugins read their own configuration from environment variables and GitHub
|
||||
* Actions inputs. Unity-builder only calls lifecycle hooks at the points where
|
||||
* an external implementation can extend or replace the local build flow.
|
||||
*/
|
||||
export interface Plugin {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
initialize(coreParameters: Record<string, any>, workspace: string): Promise<void>;
|
||||
|
||||
/** Whether the plugin wants to handle the entire build. */
|
||||
canHandleBuild(): boolean;
|
||||
|
||||
/**
|
||||
* Execute the build when canHandleBuild() returns true.
|
||||
* If the plugin needs to fall back to a local build, it returns
|
||||
* { exitCode: -1, fallbackToLocal: true }.
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
handleBuild(baseImage: string): Promise<{ exitCode: number; fallbackToLocal?: boolean }>;
|
||||
|
||||
/** Pre-build hook for local builds. */
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
beforeLocalBuild(workspace: string): Promise<void>;
|
||||
|
||||
/** Post-build hook for local builds. */
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
afterLocalBuild(workspace: string, exitCode: number): Promise<void>;
|
||||
|
||||
/** Post-build hook for all build types. */
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
handlePostBuild(exitCode: number): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to load the default optional plugin.
|
||||
*
|
||||
* Today the default implementation is @game-ci/orchestrator. The loader is
|
||||
* intentionally named after the generic plugin contract so additional plugin
|
||||
* implementations can be added without making orchestrator part of the core
|
||||
* abstraction.
|
||||
*/
|
||||
export async function loadPlugin(moduleName = DEFAULT_PLUGIN_MODULE): Promise<Plugin | undefined> {
|
||||
try {
|
||||
const pluginModule = await import(/* webpackIgnore: true */ moduleName);
|
||||
|
||||
if (typeof pluginModule.createPlugin !== 'function') {
|
||||
core.warning(
|
||||
`Plugin package "${moduleName}" found but does not export createPlugin(). ` +
|
||||
'Update the plugin package to the latest version.',
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return pluginModule.createPlugin();
|
||||
} catch (error) {
|
||||
if (!isModuleNotFoundError(error)) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isModuleNotFoundError(error: unknown): boolean {
|
||||
if (error && typeof error === 'object' && 'code' in error) {
|
||||
const code = (error as { code: string }).code;
|
||||
if (code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return typeof (error as Error)?.message === 'string' && /cannot find module/i.test((error as Error).message);
|
||||
}
|
||||
14
src/types/game-ci-orchestrator.d.ts
vendored
14
src/types/game-ci-orchestrator.d.ts
vendored
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* Type declarations for @game-ci/orchestrator.
|
||||
*
|
||||
* This optional dependency provides remote build orchestration and plugin
|
||||
* services. When installed, the plugin loader in orchestrator-plugin.ts
|
||||
* This optional dependency is one implementation of unity-builder's generic
|
||||
* plugin lifecycle. When installed, the plugin loader in plugin.ts
|
||||
* dynamically imports it.
|
||||
*/
|
||||
declare module '@game-ci/orchestrator' {
|
||||
interface OrchestratorPlugin {
|
||||
interface Plugin {
|
||||
initialize(coreParams: Record<string, any>, workspace: string): Promise<void>;
|
||||
canHandleBuild(): boolean;
|
||||
handleBuild(baseImage: string): Promise<{ exitCode: number; fallbackToLocal?: boolean }>;
|
||||
@@ -16,11 +16,11 @@ declare module '@game-ci/orchestrator' {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an orchestrator plugin instance.
|
||||
* The plugin reads its own configuration from environment variables
|
||||
* and GitHub Actions inputs — unity-builder does not need to proxy them.
|
||||
* Create a unity-builder plugin instance.
|
||||
* The plugin reads its own configuration from environment variables and
|
||||
* GitHub Actions inputs; unity-builder does not need to proxy them.
|
||||
*/
|
||||
export function createPlugin(): OrchestratorPlugin;
|
||||
export function createPlugin(): Plugin;
|
||||
|
||||
// Legacy export — kept for backward compatibility with CLI and direct consumers
|
||||
export const Orchestrator: {
|
||||
|
||||
Reference in New Issue
Block a user