diff --git a/__tests__/transport.test.ts b/__tests__/transport.test.ts index fd1f8bb..46a5efd 100644 --- a/__tests__/transport.test.ts +++ b/__tests__/transport.test.ts @@ -1,4 +1,5 @@ import * as transport from '../src/transport' +import { RpcTransport } from '../src/config' describe('action transport tools', () => { beforeEach(() => { @@ -9,4 +10,14 @@ describe('action transport tools', () => { const engine = transport.obtainTransport() expect(engine).not.toBeNull() }) + + it('can provide a configured rpc transport (grpc)', async () => { + const engine = transport.obtainTransport(RpcTransport.GRPC) + expect(engine).not.toBeNull() + }) + + it('can provide a configured rpc transport (connect)', async () => { + const engine = transport.obtainTransport(RpcTransport.CONNECT) + expect(engine).not.toBeNull() + }) }) diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js index b07306b..af0ae90 100644 --- a/dist/cleanup/index.js +++ b/dist/cleanup/index.js @@ -45641,10 +45641,11 @@ async function resolveAgentConfig(os) { * Read any available agent configuration for the provided OS, or return `null`; * this version memoizes the first call to read the configuration. * - * @param os OS to read configuration for. + * @param target OS to read configuration for. * @return Configuration (resolved from the known location), or `null`. */ -async function agentConfig(os) { +async function agentConfig(target) { + const os = target || (0, config_1.currentOs)(); if (activeAgent === null && !queriedForAgent) { queriedForAgent = true; activeAgent = await resolveAgentConfig(os); @@ -45701,6 +45702,8 @@ const node_path_1 = __importDefault(__nccwpck_require__(9411)); const child_process_1 = __importDefault(__nccwpck_require__(2081)); const core = __importStar(__nccwpck_require__(6813)); const exec = __importStar(__nccwpck_require__(2364)); +const wait_1 = __importDefault(__nccwpck_require__(9787)); +const agent_1 = __nccwpck_require__(9013); // Whether to spawn the agent directly (in Node), or through the CLI. const SPAWN_DIRECT = true; class CliError extends Error { @@ -45852,31 +45855,58 @@ async function agentStatus() { return result; } exports.agentStatus = agentStatus; +async function spawnDirect() { + core.debug('Starting Buildless Agent via background spawn'); + try { + const out = node_fs_1.default.openSync(tempPathForOs('buildless-agent.out'), 'a'); + const err = node_fs_1.default.openSync(tempPathForOs('buildless-agent.err'), 'a'); + const spawnedAgent = await spawnInBackground(BuildlessCommand.AGENT_RUN, [BuildlessArgument.BACKGROUND], [ + BuildlessArgument.VERBOSE // always spawn with verbose mode active + ], { + stdio: ['ignore', out, err] + }); + if (!spawnedAgent.success) { + console.error(`Agent spawn completed but reported failure. Please see logs in debug mode.`); + } + return spawnedAgent.pid; + } + catch (err) { + console.error(`Failed to start agent (direct: ${SPAWN_DIRECT})`, err); + throw err; + } +} +async function spawnViaCli() { + core.debug('Starting Buildless Agent via CLI'); + const started = await execBuildless(BuildlessCommand.AGENT_START); + if (started.exitCode === 0) { + await (0, wait_1.default)(1500); // give the agent 1.5s to start up + // then resolve config + const config = await (0, agent_1.agentConfig)(); + if (!config) { + console.error(`CLI reported that agent started, but could not resolve config.`); + throw new Error('Agent started but could not resolve configuration'); + } + else { + core.debug(`Started agent via CLI at PID ${config.pid}`); + return config.pid; + } + } + else { + console.error(`CLI reported that agent failed to start (exit code: ${started.exitCode})`); + throw new Error('Agent failed to start via CLI'); + } +} /** * Ask the Buildless CLI to start the agent. * - * @return Promise which resolves to an answer about whether the agent installed. + * @return Promise which resolves to the agent PID. */ async function agentStart() { - core.debug(`Starting agent via CLI`); if (SPAWN_DIRECT) { - try { - const out = node_fs_1.default.openSync(tempPathForOs('buildless-agent.out'), 'a'); - const err = node_fs_1.default.openSync(tempPathForOs('buildless-agent.err'), 'a'); - await spawnInBackground(BuildlessCommand.AGENT_RUN, [BuildlessArgument.BACKGROUND], [ - BuildlessArgument.VERBOSE // always spawn with verbose mode active - ], { - stdio: ['ignore', out, err] - }); - return true; - } - catch (err) { - console.error(`Failed to start agent (direct: ${SPAWN_DIRECT})`, err); - return false; - } + return await spawnDirect(); } else { - return (await execBuildless(BuildlessCommand.AGENT_START)).exitCode === 0; + return await spawnViaCli(); } } exports.agentStart = agentStart; @@ -45924,7 +45954,7 @@ exports.setBinpath = setBinpath; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.TRANSPORT = exports.Arch = exports.OS = exports.RpcTransport = exports.BUILDLESS_AZR_ENDPOINT = exports.BUILDLESS_AGENT_ENDPOINT = exports.BUILDLESS_EDGE_ENDPOINT = exports.BUILDLESS_GLOBAL_ENDPOINT = exports.GITHUB_DEFAULT_HEADERS = exports.GITHUB_API_VERSION = void 0; +exports.currentOs = exports.TRANSPORT = exports.Arch = exports.OS = exports.RpcTransport = exports.BUILDLESS_AZR_ENDPOINT = exports.BUILDLESS_AGENT_ENDPOINT = exports.BUILDLESS_EDGE_ENDPOINT = exports.BUILDLESS_GLOBAL_ENDPOINT = exports.GITHUB_DEFAULT_HEADERS = exports.GITHUB_API_VERSION = void 0; // Version of the GitHub API to use. exports.GITHUB_API_VERSION = '2022-11-28'; // Default headers to send on GitHub API requests. @@ -45971,6 +46001,22 @@ var Arch; })(Arch || (exports.Arch = Arch = {})); // Default transport mode. exports.TRANSPORT = RpcTransport.GRPC; +/** + * Resolve the OS instance for the current (host) operating system. + * + * @returns Current OS enum instance. + */ +function currentOs() { + switch (process.platform) { + case 'darwin': + return OS.MACOS; + case 'win32': + return OS.WINDOWS; + default: + return OS.LINUX; + } +} +exports.currentOs = currentOs; exports["default"] = { githubApiVersion: exports.GITHUB_API_VERSION, githubDefaultHeaders: exports.GITHUB_DEFAULT_HEADERS, @@ -46012,16 +46058,12 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.cleanup = exports.entry = exports.postExecute = exports.install = exports.resolveExistingBinary = exports.buildEffectiveOptions = exports.postInstall = exports.notSupported = exports.setActionEffectiveOptions = void 0; const core = __importStar(__nccwpck_require__(6813)); const io = __importStar(__nccwpck_require__(7053)); const outputs_1 = __nccwpck_require__(219); const command_1 = __nccwpck_require__(4561); -const wait_1 = __importDefault(__nccwpck_require__(9787)); const config_1 = __nccwpck_require__(5463); const agent_1 = __nccwpck_require__(9013); const options_1 = __importStar(__nccwpck_require__(5932)); @@ -46206,7 +46248,7 @@ async function install(options, withinAction = true) { } // if instructed, add binary to the path if (effectiveOptions.export_path && withinAction) { - core.info(`Adding '${release.path}' to PATH`); + core.info(`Adding '${release.home}' to PATH`); core.addPath(release.home); } else { @@ -46248,10 +46290,11 @@ async function install(options, withinAction = true) { core.notice('The Buildless Agent failed to install; please see CI logs for more info.'); installFailed = true; } + let pid = -1; if (!installFailed) { core.debug('Agent installation complete. Starting agent...'); try { - await (0, agent_1.agentStart)(); + pid = await (0, agent_1.agentStart)(); } catch (err) { core.notice('The Buildless Agent installed, but failed to start; please see CI logs for more info.'); @@ -46259,7 +46302,13 @@ async function install(options, withinAction = true) { } } if (!installFailed && !startFailed) { - core.debug('Agent installed and started.'); + const cfg = await (0, agent_1.agentConfig)(); + if (!cfg) { + console.warn(`Agent started at PID ${pid}, but config failed to resolve. Caching may not work.`); + } + else { + core.debug(`Agent installed and started at PID: ${pid}.`); + } agentEnabled = true; agentManaged = true; } @@ -46268,9 +46317,6 @@ async function install(options, withinAction = true) { } let activeAgent = null; if (agentEnabled && agentManaged) { - if (agentManaged) { - await (0, wait_1.default)(1500); // give the agent 1.5s to start up - } try { activeAgent = await (0, agent_1.agentConfig)(targetOs); } diff --git a/dist/index.js b/dist/index.js index 5cefadd..33a9323 100644 --- a/dist/index.js +++ b/dist/index.js @@ -45641,10 +45641,11 @@ async function resolveAgentConfig(os) { * Read any available agent configuration for the provided OS, or return `null`; * this version memoizes the first call to read the configuration. * - * @param os OS to read configuration for. + * @param target OS to read configuration for. * @return Configuration (resolved from the known location), or `null`. */ -async function agentConfig(os) { +async function agentConfig(target) { + const os = target || (0, config_1.currentOs)(); if (activeAgent === null && !queriedForAgent) { queriedForAgent = true; activeAgent = await resolveAgentConfig(os); @@ -45701,6 +45702,8 @@ const node_path_1 = __importDefault(__nccwpck_require__(9411)); const child_process_1 = __importDefault(__nccwpck_require__(2081)); const core = __importStar(__nccwpck_require__(6813)); const exec = __importStar(__nccwpck_require__(2364)); +const wait_1 = __importDefault(__nccwpck_require__(9787)); +const agent_1 = __nccwpck_require__(9013); // Whether to spawn the agent directly (in Node), or through the CLI. const SPAWN_DIRECT = true; class CliError extends Error { @@ -45852,31 +45855,58 @@ async function agentStatus() { return result; } exports.agentStatus = agentStatus; +async function spawnDirect() { + core.debug('Starting Buildless Agent via background spawn'); + try { + const out = node_fs_1.default.openSync(tempPathForOs('buildless-agent.out'), 'a'); + const err = node_fs_1.default.openSync(tempPathForOs('buildless-agent.err'), 'a'); + const spawnedAgent = await spawnInBackground(BuildlessCommand.AGENT_RUN, [BuildlessArgument.BACKGROUND], [ + BuildlessArgument.VERBOSE // always spawn with verbose mode active + ], { + stdio: ['ignore', out, err] + }); + if (!spawnedAgent.success) { + console.error(`Agent spawn completed but reported failure. Please see logs in debug mode.`); + } + return spawnedAgent.pid; + } + catch (err) { + console.error(`Failed to start agent (direct: ${SPAWN_DIRECT})`, err); + throw err; + } +} +async function spawnViaCli() { + core.debug('Starting Buildless Agent via CLI'); + const started = await execBuildless(BuildlessCommand.AGENT_START); + if (started.exitCode === 0) { + await (0, wait_1.default)(1500); // give the agent 1.5s to start up + // then resolve config + const config = await (0, agent_1.agentConfig)(); + if (!config) { + console.error(`CLI reported that agent started, but could not resolve config.`); + throw new Error('Agent started but could not resolve configuration'); + } + else { + core.debug(`Started agent via CLI at PID ${config.pid}`); + return config.pid; + } + } + else { + console.error(`CLI reported that agent failed to start (exit code: ${started.exitCode})`); + throw new Error('Agent failed to start via CLI'); + } +} /** * Ask the Buildless CLI to start the agent. * - * @return Promise which resolves to an answer about whether the agent installed. + * @return Promise which resolves to the agent PID. */ async function agentStart() { - core.debug(`Starting agent via CLI`); if (SPAWN_DIRECT) { - try { - const out = node_fs_1.default.openSync(tempPathForOs('buildless-agent.out'), 'a'); - const err = node_fs_1.default.openSync(tempPathForOs('buildless-agent.err'), 'a'); - await spawnInBackground(BuildlessCommand.AGENT_RUN, [BuildlessArgument.BACKGROUND], [ - BuildlessArgument.VERBOSE // always spawn with verbose mode active - ], { - stdio: ['ignore', out, err] - }); - return true; - } - catch (err) { - console.error(`Failed to start agent (direct: ${SPAWN_DIRECT})`, err); - return false; - } + return await spawnDirect(); } else { - return (await execBuildless(BuildlessCommand.AGENT_START)).exitCode === 0; + return await spawnViaCli(); } } exports.agentStart = agentStart; @@ -45924,7 +45954,7 @@ exports.setBinpath = setBinpath; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.TRANSPORT = exports.Arch = exports.OS = exports.RpcTransport = exports.BUILDLESS_AZR_ENDPOINT = exports.BUILDLESS_AGENT_ENDPOINT = exports.BUILDLESS_EDGE_ENDPOINT = exports.BUILDLESS_GLOBAL_ENDPOINT = exports.GITHUB_DEFAULT_HEADERS = exports.GITHUB_API_VERSION = void 0; +exports.currentOs = exports.TRANSPORT = exports.Arch = exports.OS = exports.RpcTransport = exports.BUILDLESS_AZR_ENDPOINT = exports.BUILDLESS_AGENT_ENDPOINT = exports.BUILDLESS_EDGE_ENDPOINT = exports.BUILDLESS_GLOBAL_ENDPOINT = exports.GITHUB_DEFAULT_HEADERS = exports.GITHUB_API_VERSION = void 0; // Version of the GitHub API to use. exports.GITHUB_API_VERSION = '2022-11-28'; // Default headers to send on GitHub API requests. @@ -45971,6 +46001,22 @@ var Arch; })(Arch || (exports.Arch = Arch = {})); // Default transport mode. exports.TRANSPORT = RpcTransport.GRPC; +/** + * Resolve the OS instance for the current (host) operating system. + * + * @returns Current OS enum instance. + */ +function currentOs() { + switch (process.platform) { + case 'darwin': + return OS.MACOS; + case 'win32': + return OS.WINDOWS; + default: + return OS.LINUX; + } +} +exports.currentOs = currentOs; exports["default"] = { githubApiVersion: exports.GITHUB_API_VERSION, githubDefaultHeaders: exports.GITHUB_DEFAULT_HEADERS, @@ -46012,16 +46058,12 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.cleanup = exports.entry = exports.postExecute = exports.install = exports.resolveExistingBinary = exports.buildEffectiveOptions = exports.postInstall = exports.notSupported = exports.setActionEffectiveOptions = void 0; const core = __importStar(__nccwpck_require__(6813)); const io = __importStar(__nccwpck_require__(7053)); const outputs_1 = __nccwpck_require__(219); const command_1 = __nccwpck_require__(4561); -const wait_1 = __importDefault(__nccwpck_require__(9787)); const config_1 = __nccwpck_require__(5463); const agent_1 = __nccwpck_require__(9013); const options_1 = __importStar(__nccwpck_require__(5932)); @@ -46206,7 +46248,7 @@ async function install(options, withinAction = true) { } // if instructed, add binary to the path if (effectiveOptions.export_path && withinAction) { - core.info(`Adding '${release.path}' to PATH`); + core.info(`Adding '${release.home}' to PATH`); core.addPath(release.home); } else { @@ -46248,10 +46290,11 @@ async function install(options, withinAction = true) { core.notice('The Buildless Agent failed to install; please see CI logs for more info.'); installFailed = true; } + let pid = -1; if (!installFailed) { core.debug('Agent installation complete. Starting agent...'); try { - await (0, agent_1.agentStart)(); + pid = await (0, agent_1.agentStart)(); } catch (err) { core.notice('The Buildless Agent installed, but failed to start; please see CI logs for more info.'); @@ -46259,7 +46302,13 @@ async function install(options, withinAction = true) { } } if (!installFailed && !startFailed) { - core.debug('Agent installed and started.'); + const cfg = await (0, agent_1.agentConfig)(); + if (!cfg) { + console.warn(`Agent started at PID ${pid}, but config failed to resolve. Caching may not work.`); + } + else { + core.debug(`Agent installed and started at PID: ${pid}.`); + } agentEnabled = true; agentManaged = true; } @@ -46268,9 +46317,6 @@ async function install(options, withinAction = true) { } let activeAgent = null; if (agentEnabled && agentManaged) { - if (agentManaged) { - await (0, wait_1.default)(1500); // give the agent 1.5s to start up - } try { activeAgent = await (0, agent_1.agentConfig)(targetOs); } diff --git a/src/agent.ts b/src/agent.ts index 1e0ff85..8c14254 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -1,5 +1,5 @@ import fs from 'node:fs' -import { OS } from './config' +import { OS, currentOs } from './config' import { agentStart, agentStop, agentStatus, agentInstall } from './command' export { agentStart, agentStop, agentStatus, agentInstall } from './command' @@ -53,10 +53,11 @@ async function resolveAgentConfig(os: OS): Promise { * Read any available agent configuration for the provided OS, or return `null`; * this version memoizes the first call to read the configuration. * - * @param os OS to read configuration for. + * @param target OS to read configuration for. * @return Configuration (resolved from the known location), or `null`. */ -export async function agentConfig(os: OS): Promise { +export async function agentConfig(target?: OS): Promise { + const os = target || currentOs() if (activeAgent === null && !queriedForAgent) { queriedForAgent = true activeAgent = await resolveAgentConfig(os) diff --git a/src/command.ts b/src/command.ts index cf990b0..d5a1047 100644 --- a/src/command.ts +++ b/src/command.ts @@ -4,6 +4,8 @@ import childProcess from 'child_process' import * as core from '@actions/core' import * as exec from '@actions/exec' +import wait from './wait' +import { agentConfig } from './agent' // Whether to spawn the agent directly (in Node), or through the CLI. const SPAWN_DIRECT = true @@ -213,35 +215,69 @@ export async function agentStatus(): Promise { return result } +async function spawnDirect(): Promise { + core.debug('Starting Buildless Agent via background spawn') + try { + const out = fs.openSync(tempPathForOs('buildless-agent.out'), 'a') + const err = fs.openSync(tempPathForOs('buildless-agent.err'), 'a') + + const spawnedAgent = await spawnInBackground( + BuildlessCommand.AGENT_RUN, + [BuildlessArgument.BACKGROUND], + [ + BuildlessArgument.VERBOSE // always spawn with verbose mode active + ], + { + stdio: ['ignore', out, err] + } + ) + if (!spawnedAgent.success) { + console.error( + `Agent spawn completed but reported failure. Please see logs in debug mode.` + ) + } + return spawnedAgent.pid + } catch (err) { + console.error(`Failed to start agent (direct: ${SPAWN_DIRECT})`, err) + throw err + } +} + +async function spawnViaCli(): Promise { + core.debug('Starting Buildless Agent via CLI') + const started = await execBuildless(BuildlessCommand.AGENT_START) + if (started.exitCode === 0) { + await wait(1500) // give the agent 1.5s to start up + + // then resolve config + const config = await agentConfig() + if (!config) { + console.error( + `CLI reported that agent started, but could not resolve config.` + ) + throw new Error('Agent started but could not resolve configuration') + } else { + core.debug(`Started agent via CLI at PID ${config.pid}`) + return config.pid + } + } else { + console.error( + `CLI reported that agent failed to start (exit code: ${started.exitCode})` + ) + throw new Error('Agent failed to start via CLI') + } +} + /** * Ask the Buildless CLI to start the agent. * - * @return Promise which resolves to an answer about whether the agent installed. + * @return Promise which resolves to the agent PID. */ -export async function agentStart(): Promise { - core.debug(`Starting agent via CLI`) +export async function agentStart(): Promise { if (SPAWN_DIRECT) { - try { - const out = fs.openSync(tempPathForOs('buildless-agent.out'), 'a') - const err = fs.openSync(tempPathForOs('buildless-agent.err'), 'a') - - await spawnInBackground( - BuildlessCommand.AGENT_RUN, - [BuildlessArgument.BACKGROUND], - [ - BuildlessArgument.VERBOSE // always spawn with verbose mode active - ], - { - stdio: ['ignore', out, err] - } - ) - return true - } catch (err) { - console.error(`Failed to start agent (direct: ${SPAWN_DIRECT})`, err) - return false - } + return await spawnDirect() } else { - return (await execBuildless(BuildlessCommand.AGENT_START)).exitCode === 0 + return await spawnViaCli() } } diff --git a/src/config.ts b/src/config.ts index 79fc213..9e9a314 100644 --- a/src/config.ts +++ b/src/config.ts @@ -54,6 +54,22 @@ export enum Arch { // Default transport mode. export const TRANSPORT: RpcTransport = RpcTransport.GRPC +/** + * Resolve the OS instance for the current (host) operating system. + * + * @returns Current OS enum instance. + */ +export function currentOs(): OS { + switch (process.platform) { + case 'darwin': + return OS.MACOS + case 'win32': + return OS.WINDOWS + default: + return OS.LINUX + } +} + export default { githubApiVersion: GITHUB_API_VERSION, githubDefaultHeaders: GITHUB_DEFAULT_HEADERS, diff --git a/src/main.ts b/src/main.ts index 7b76a16..ebbf2d0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,7 +5,6 @@ import { BuildlessSetupActionOutputs as Outputs } from './outputs' import { BuildlessArgument, obtainVersion, setBinpath } from './command' -import wait from './wait' import { OS } from './config' import { agentStart, @@ -258,7 +257,7 @@ export async function install( // if instructed, add binary to the path if (effectiveOptions.export_path && withinAction) { - core.info(`Adding '${release.path}' to PATH`) + core.info(`Adding '${release.home}' to PATH`) core.addPath(release.home) } else { core.debug('Skipping add-binary-to-path step (turned off)') @@ -308,10 +307,11 @@ export async function install( ) installFailed = true } + let pid = -1 if (!installFailed) { core.debug('Agent installation complete. Starting agent...') try { - await agentStart() + pid = await agentStart() } catch (err) { core.notice( 'The Buildless Agent installed, but failed to start; please see CI logs for more info.' @@ -320,7 +320,14 @@ export async function install( } } if (!installFailed && !startFailed) { - core.debug('Agent installed and started.') + const cfg = await agentConfig() + if (!cfg) { + console.warn( + `Agent started at PID ${pid}, but config failed to resolve. Caching may not work.` + ) + } else { + core.debug(`Agent installed and started at PID: ${pid}.`) + } agentEnabled = true agentManaged = true } @@ -330,9 +337,6 @@ export async function install( let activeAgent = null if (agentEnabled && agentManaged) { - if (agentManaged) { - await wait(1500) // give the agent 1.5s to start up - } try { activeAgent = await agentConfig(targetOs) } catch (err) { diff --git a/src/transport.ts b/src/transport.ts index 5e927f4..214a2ca 100644 --- a/src/transport.ts +++ b/src/transport.ts @@ -28,8 +28,8 @@ const connectTransport = createConnectTransport(transportSettings as any) * * @returns RPC transport to use. */ -export function obtainTransport(): Transport { - switch (activeTransport) { +export function obtainTransport(override?: RpcTransport): Transport { + switch (override || activeTransport) { case RpcTransport.CONNECT: return connectTransport case RpcTransport.GRPC: