diff --git a/rush-plugins/rush-http-build-cache-plugin/src/HttpBuildCacheProvider.test.ts b/rush-plugins/rush-http-build-cache-plugin/src/HttpBuildCacheProvider.test.ts index 20da3767c5e..d409f623170 100644 --- a/rush-plugins/rush-http-build-cache-plugin/src/HttpBuildCacheProvider.test.ts +++ b/rush-plugins/rush-http-build-cache-plugin/src/HttpBuildCacheProvider.test.ts @@ -9,7 +9,10 @@ import { StringBufferTerminalProvider, Terminal } from '@rushstack/node-core-lib const EXAMPLE_OPTIONS = { url: 'https://buildcache.example.acme.com', - tokenHandler: 'node tokenHandler.js', + tokenHandler: { + exec: 'node', + args: ['tokenHandler.js'] + }, uploadMethod: 'POST', isCacheWriteAllowed: false, pluginName: 'example-plugin', diff --git a/rush-plugins/rush-http-build-cache-plugin/src/HttpBuildCacheProvider.ts b/rush-plugins/rush-http-build-cache-plugin/src/HttpBuildCacheProvider.ts index e34d9f3d485..9cb8e90565f 100644 --- a/rush-plugins/rush-http-build-cache-plugin/src/HttpBuildCacheProvider.ts +++ b/rush-plugins/rush-http-build-cache-plugin/src/HttpBuildCacheProvider.ts @@ -1,4 +1,4 @@ -import { ITerminal } from '@rushstack/node-core-library'; +import { ITerminal, Executable } from '@rushstack/node-core-library'; import { ICloudBuildCacheProvider, ICredentialCacheEntry, @@ -7,7 +7,6 @@ import { EnvironmentConfiguration } from '@rushstack/rush-sdk'; import fetch, { BodyInit, Response } from 'node-fetch'; -import { exec } from './exec'; enum CredentialsOptions { Optional, @@ -23,12 +22,17 @@ enum FailureType { Authentication } +export interface IHttpBuildCacheTokenHandler { + exec: string; + args?: string[]; +} + /** * @public */ export interface IHttpBuildCacheProviderOptions { url: string; - tokenHandler?: string; + tokenHandler?: IHttpBuildCacheTokenHandler; uploadMethod?: string; headers?: Record; cacheKeyPrefix?: string; @@ -47,7 +51,7 @@ export class HttpBuildCacheProvider implements ICloudBuildCacheProvider { private readonly _uploadMethod: string; private readonly _headers: Record; private readonly _cacheKeyPrefix: string; - private readonly _tokenHandler: string | undefined; + private readonly _tokenHandler: IHttpBuildCacheTokenHandler | undefined; private __credentialCacheId: string | undefined; public get isCacheWriteAllowed(): boolean { @@ -133,7 +137,7 @@ export class HttpBuildCacheProvider implements ICloudBuildCacheProvider { } public async updateCachedCredentialInteractiveAsync(terminal: ITerminal): Promise { - if (typeof this._tokenHandler !== 'string') { + if (!this._tokenHandler) { throw new Error( `The interactive cloud credentials flow is not configured.\n` + `Set the 'tokenHandler' setting in 'common/config/rush-plugins/${this._pluginName}.json' to a command that writes your credentials to standard output and exits with code 0 ` + @@ -142,9 +146,9 @@ export class HttpBuildCacheProvider implements ICloudBuildCacheProvider { ); } - const cmd: string = this._tokenHandler; + const cmd: string = `${this._tokenHandler.exec} ${(this._tokenHandler.args || []).join(' ')}`; terminal.writeVerboseLine(`Running '${cmd}' to get credentials`); - const result = await exec(cmd, this._rushProjectRoot); + const result = Executable.spawnSync(this._tokenHandler.exec, this._tokenHandler.args || []); terminal.writeErrorLine(result.stderr); diff --git a/rush-plugins/rush-http-build-cache-plugin/src/RushHttpBuildCachePlugin.ts b/rush-plugins/rush-http-build-cache-plugin/src/RushHttpBuildCachePlugin.ts index 18ade9e9790..5a248e64387 100644 --- a/rush-plugins/rush-http-build-cache-plugin/src/RushHttpBuildCachePlugin.ts +++ b/rush-plugins/rush-http-build-cache-plugin/src/RushHttpBuildCachePlugin.ts @@ -29,9 +29,13 @@ export interface IRushHttpBuildCachePluginOptions { headers?: Record; /** - * An optional command that prints the endpoint's credentials to stdout. + * An optional command that prints the endpoint's credentials to stdout. Provide the + * command or script to execute and, optionally, any arguments to pass to the script. */ - tokenHandler?: string; + tokenHandler?: { + exec: string; + args?: string[]; + }; /** * Prefix for cache keys. diff --git a/rush-plugins/rush-http-build-cache-plugin/src/exec.test.ts b/rush-plugins/rush-http-build-cache-plugin/src/exec.test.ts deleted file mode 100644 index 309806fcfbd..00000000000 --- a/rush-plugins/rush-http-build-cache-plugin/src/exec.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { exec } from './exec'; - -describe('exec', function () { - it('can exec a process and capture output', async function () { - // Act - const cmd = process.argv0 + ` --eval "console.log(1); console.error(2); process.exit(3);"`; - const result = await exec(cmd, process.cwd()); - - expect(result.error?.message).toEqual(`Command failed: ${cmd}\n2\n`); - expect(result.stderr).toEqual('2\n'); - expect(result.stdout).toEqual('1\n'); - }); -}); diff --git a/rush-plugins/rush-http-build-cache-plugin/src/exec.ts b/rush-plugins/rush-http-build-cache-plugin/src/exec.ts deleted file mode 100644 index 6952df1aee6..00000000000 --- a/rush-plugins/rush-http-build-cache-plugin/src/exec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { exec as child_process_exec } from 'child_process'; - -/** - * The result of spawning a command - */ -export interface IExecResult { - /** - * The standard output of the spawned command - */ - stdout: string; - - /** - * The standard error of the spawned command - */ - stderr: string; - - /** - * The exit code of the spawned command - */ - error?: Error; -} - -/** - * Spawn a child process and obtain the contents of its output streams as text - * @param cmd - Command to execute - * @param args - Arguments to pass to command - * @returns The exit code and output of the executed command - */ -export function exec(cmd: string, cwd: string): Promise { - return new Promise(function (resolve: (result: IExecResult) => void, reject: (error: unknown) => void) { - child_process_exec(cmd, { cwd }, function (error, stdout, stderr) { - resolve({ stdout, stderr, error: error || undefined }); - }); - }); -} diff --git a/rush-plugins/rush-http-build-cache-plugin/src/schemas/plugin-config.schema.json b/rush-plugins/rush-http-build-cache-plugin/src/schemas/plugin-config.schema.json index fc4048a2369..abd50212fa2 100644 --- a/rush-plugins/rush-http-build-cache-plugin/src/schemas/plugin-config.schema.json +++ b/rush-plugins/rush-http-build-cache-plugin/src/schemas/plugin-config.schema.json @@ -24,8 +24,21 @@ } }, "tokenHandler": { - "type": "string", - "description": "(Optional) Shell command that prints the authorization token needed to communicate with the HTTPS server and exits with code 0. This command will be executed from the root of the monorepo." + "type": "object", + "description": "(Optional) Shell command that prints the authorization token needed to communicate with the HTTPS server and exits with code 0. This command will be executed from the root of the monorepo.", + "properties": { + "exec": { + "type": "string", + "description": "(Required) The command or script to execute." + }, + "args": { + "type": "array", + "description": "(Optional) Arguments to pass to the command or script.", + "items": { + "type": "string" + } + } + } }, "cacheKeyPrefix": { "type": "string",