Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Remove state from context
  • Loading branch information
nikolai-laevskii committed Oct 12, 2023
commit 36629a3962343189e7d67e487793f04120b69902
13 changes: 5 additions & 8 deletions packages/helpers/__tests__/command-runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,13 @@ describe('command-runner', () => {

expect(middleware).toHaveBeenCalledWith(
expect.objectContaining({
commandLine: 'echo',
args: ['hello', 'world'],
options: expect.objectContaining({
silent: true
}),
stdout: 'hello',
stderr: '',
exitCode: 0,
commandLine: 'echo',
execerr: null,
state: null
exitCode: 0,
options: {failOnStdErr: false, ignoreReturnCode: true, silent: true},
stderr: '',
stdout: 'hello'
}),
expect.any(Function)
)
Expand Down
48 changes: 18 additions & 30 deletions packages/helpers/src/command-runner/command-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,131 +25,119 @@ const commandRunnerActions = {
log: produceLog
} as const

export class CommandRunner<S = unknown> extends CommandRunnerBase<S> {
export class CommandRunner extends CommandRunnerBase {
on(
event: CommandRunnerEventTypeExtended | CommandRunnerEventTypeExtended[],
action: CommandRunnerActionType | CommandRunnerMiddleware<S>,
action: CommandRunnerActionType | CommandRunnerMiddleware,
message?: string
): this {
const middleware =
typeof action === 'string'
? [commandRunnerActions[action](message)]
: [action]

this.use(matchEvent(event, middleware as CommandRunnerMiddleware[]))
this.use(matchEvent(event, middleware))
return this
}

onEmptyOutput(
action: CommandRunnerActionType | CommandRunnerMiddleware<S>,
action: CommandRunnerActionType | CommandRunnerMiddleware,
message?: string
): this {
this.onOutput(stdout => stdout?.trim() === '', action, message)
return this
}

onExecutionError(
action: CommandRunnerActionType | CommandRunnerMiddleware<S>,
action: CommandRunnerActionType | CommandRunnerMiddleware,
message?: string
): this {
const middleware =
typeof action === 'string'
? [commandRunnerActions[action](message)]
: [action]

this.use(
matchSpecificError(
({type}) => type === 'execerr',
middleware as CommandRunnerMiddleware[]
)
)
this.use(matchSpecificError(({type}) => type === 'execerr', middleware))

return this
}

onStdError(
action: CommandRunnerActionType | CommandRunnerMiddleware<S>,
action: CommandRunnerActionType | CommandRunnerMiddleware,
message?: string
): this {
const middleware =
typeof action === 'string'
? [commandRunnerActions[action](message)]
: [action]

this.use(
matchSpecificError(
({type}) => type === 'stderr',
middleware as CommandRunnerMiddleware[]
)
)
this.use(matchSpecificError(({type}) => type === 'stderr', middleware))

return this
}

onError(
action: CommandRunnerActionType | CommandRunnerMiddleware<S>,
action: CommandRunnerActionType | CommandRunnerMiddleware,
message?: string
): this {
return this.on(['execerr', 'stderr'], action, message)
}

onSpecificError(
matcher: ErrorMatcher,
action: CommandRunnerActionType | CommandRunnerMiddleware<S>,
action: CommandRunnerActionType | CommandRunnerMiddleware,
message?: string
): this {
const middleware =
typeof action === 'string'
? [commandRunnerActions[action](message)]
: [action]

this.use(
matchSpecificError(matcher, middleware as CommandRunnerMiddleware[])
)
this.use(matchSpecificError(matcher, middleware))

return this
}

onSuccess(
action: CommandRunnerActionType | CommandRunnerMiddleware<S>,
action: CommandRunnerActionType | CommandRunnerMiddleware,
message?: string
): this {
return this.on('ok', action, message)
}

onExitCode(
matcher: ExitCodeMatcher,
action: CommandRunnerActionType | CommandRunnerMiddleware<S>,
action: CommandRunnerActionType | CommandRunnerMiddleware,
message?: string
): this {
const middleware =
typeof action === 'string'
? [commandRunnerActions[action](message)]
: [action]

this.use(matchExitCode(matcher, middleware as CommandRunnerMiddleware[]))
this.use(matchExitCode(matcher, middleware))

return this
}

onOutput(
matcher: OutputMatcher,
action: CommandRunnerActionType | CommandRunnerMiddleware<S>,
action: CommandRunnerActionType | CommandRunnerMiddleware,
message?: string
): this {
const middleware =
typeof action === 'string'
? [commandRunnerActions[action](message)]
: [action]

this.use(matchOutput(matcher, middleware as CommandRunnerMiddleware[]))
this.use(matchOutput(matcher, middleware))

return this
}
}

export const createCommandRunner = <S = unknown>(
export const createCommandRunner = (
commandLine: string,
args: string[] = [],
options: CommandRunnerOptions = {}
): CommandRunner<S> => new CommandRunner(commandLine, args, options, exec.exec)
): CommandRunner => new CommandRunner(commandLine, args, options, exec.exec)
21 changes: 7 additions & 14 deletions packages/helpers/src/command-runner/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import {
} from './types'

export const promisifyCommandRunnerMiddleware =
(
middleware: CommandRunnerMiddleware<unknown>
): CommandRunnerMiddlewarePromisified =>
(middleware: CommandRunnerMiddleware): CommandRunnerMiddlewarePromisified =>
async (ctx, next) => {
return Promise.resolve(middleware(ctx, next))
}
Expand All @@ -36,7 +34,7 @@ export const composeCommandRunnerMiddleware =
await nextLocal()
}

export class CommandRunnerBase<S = unknown> {
export class CommandRunnerBase {
private middleware: CommandRunnerMiddlewarePromisified[] = []

constructor(
Expand All @@ -46,12 +44,8 @@ export class CommandRunnerBase<S = unknown> {
private executor: typeof exec.exec = exec.exec
) {}

use(middleware: CommandRunnerMiddleware<S>): this {
this.middleware.push(
promisifyCommandRunnerMiddleware(
middleware as CommandRunnerMiddleware<unknown>
)
)
use(middleware: CommandRunnerMiddleware): this {
this.middleware.push(promisifyCommandRunnerMiddleware(middleware))
return this
}

Expand All @@ -64,21 +58,20 @@ export class CommandRunnerBase<S = unknown> {

/* overrides options for this specific execution if not undefined */
options?: CommandRunnerOptions
): Promise<CommandRunnerContext<S>> {
): Promise<CommandRunnerContext> {
const requiredOptions: exec.ExecOptions = {
ignoreReturnCode: true,
failOnStdErr: false
}

const context: CommandRunnerContext<S> = {
const context: CommandRunnerContext = {
commandLine: commandLine ?? this.commandLine,
args: args ?? this.args,
options: {...(options ?? this.options), ...requiredOptions},
stdout: null,
stderr: null,
execerr: null,
exitCode: null,
state: null
exitCode: null
}

try {
Expand Down
9 changes: 3 additions & 6 deletions packages/helpers/src/command-runner/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as exec from '@actions/exec'

/* CommandRunner core */

export interface CommandRunnerContext<S = unknown> {
export interface CommandRunnerContext {
/* Inputs with which command was executed */
commandLine: string
args: string[]
Expand All @@ -13,9 +13,6 @@ export interface CommandRunnerContext<S = unknown> {
stderr: string | null
stdout: string | null
exitCode: number | null

/* Arbitrary state that can be change during middleware execution if needed */
state: S | null
}

/* Middlewares as used internally in CommandRunner */
Expand All @@ -25,8 +22,8 @@ export type CommandRunnerMiddlewarePromisified = (
) => Promise<void>

/* Middlewares as used by the user */
export type CommandRunnerMiddleware<S = unknown> = (
ctx: CommandRunnerContext<S>,
export type CommandRunnerMiddleware = (
ctx: CommandRunnerContext,
next: () => Promise<void>
) => void | Promise<void>

Expand Down