From 5ee07e0a46150757bbfb6381cc49263ffddf56ec Mon Sep 17 00:00:00 2001 From: Umberto Pepato Date: Sat, 24 Apr 2021 11:55:19 +0200 Subject: [PATCH] fix(hooks): forward git hooks through a variable to avoid breaking scripts --- scripts.yml | 4 +- src/cli/commands/run.ts | 9 ++- src/cli/commands/run_hook.ts | 10 ++- src/cli/commands/vr.ts | 9 ++- src/run_commands.ts | 117 +++++++++++++++++++++++++---------- src/run_script.ts | 27 ++++++-- src/util.ts | 2 + 7 files changed, 135 insertions(+), 43 deletions(-) diff --git a/scripts.yml b/scripts.yml index 5a6149f..82c6707 100644 --- a/scripts.yml +++ b/scripts.yml @@ -1,7 +1,7 @@ scripts: test: - cmd: 'deno test -Ar #' + cmd: deno test -Ar desc: Runs the tests gitHook: pre-push @@ -15,6 +15,6 @@ scripts: gitHook: pre-commit commitlint: - cmd: npx commitlint -x @commitlint/config-conventional -e $1 + cmd: echo "Args ${GIT_ARGS[1]}"; npx commitlint -x @commitlint/config-conventional -e ${GIT_ARGS[1]} desc: Checks commit messages format gitHook: commit-msg diff --git a/src/cli/commands/run.ts b/src/cli/commands/run.ts index 740d399..84d3730 100644 --- a/src/cli/commands/run.ts +++ b/src/cli/commands/run.ts @@ -1,6 +1,6 @@ import { Command } from "../../../deps.ts"; import { ConfigData } from "../../load_config.ts"; -import { runScript } from "../../run_script.ts"; +import { ArgsForwardingMode, runScript } from "../../run_script.ts"; import { checkGitHooks } from "../../git_hooks.ts"; import { validateConfigData } from "../../validate_config_data.ts"; @@ -17,7 +17,12 @@ export class RunCommand extends Command { } validateConfigData(this.configData); await checkGitHooks(this.configData as ConfigData); - await runScript(this.configData as ConfigData, script, additionalArgs); + await runScript({ + configData: this.configData!, + script, + additionalArgs, + argsForwardingMode: ArgsForwardingMode.DIRECT, + }); }); } } diff --git a/src/cli/commands/run_hook.ts b/src/cli/commands/run_hook.ts index 9b04555..cfba6e3 100644 --- a/src/cli/commands/run_hook.ts +++ b/src/cli/commands/run_hook.ts @@ -1,6 +1,6 @@ import { Command } from "../../../deps.ts"; import { ConfigData } from "../../load_config.ts"; -import { runScript } from "../../run_script.ts"; +import { ArgsForwardingMode, runScript } from "../../run_script.ts"; import { VR_HOOKS } from "../../consts.ts"; import { validateConfigData } from "../../validate_config_data.ts"; import { isScriptObject } from "../../util.ts"; @@ -21,7 +21,13 @@ export class RunHookCommand extends Command { value.gitHook === hook ); if (script) { - await runScript(this.configData, script[0], args); + await runScript({ + configData: this.configData!, + script: script[0], + prefix: `GIT_ARGS=("$@");`, + additionalArgs: args, + argsForwardingMode: ArgsForwardingMode.INDIRECT, + }); } } }); diff --git a/src/cli/commands/vr.ts b/src/cli/commands/vr.ts index 014fd6e..dc50ab1 100644 --- a/src/cli/commands/vr.ts +++ b/src/cli/commands/vr.ts @@ -4,7 +4,7 @@ import { ScriptIdType } from "../types/script_id_type.ts"; import { ConfigData } from "../../load_config.ts"; import { RunCommand } from "./run.ts"; import { ExportCommand } from "./export.ts"; -import { runScript } from "../../run_script.ts"; +import { ArgsForwardingMode, runScript } from "../../run_script.ts"; import { RunHookCommand } from "./run_hook.ts"; import { VR_HOOKS, VR_LOG, VR_SHELL } from "../../consts.ts"; import { checkGitHooks } from "../../git_hooks.ts"; @@ -37,7 +37,12 @@ export class VrCommand extends Command { .action(async (options, script: string, additionalArgs: string[]) => { validateConfigData(this.configData); await checkGitHooks(this.configData as ConfigData); - await runScript(this.configData as ConfigData, script, additionalArgs); + await runScript({ + configData: this.configData!, + script, + additionalArgs, + argsForwardingMode: ArgsForwardingMode.DIRECT, + }); }) .command("run", new RunCommand(this.configData)) .command("run-hook", new RunHookCommand(this.configData)) diff --git a/src/run_commands.ts b/src/run_commands.ts index f95166b..2b924e2 100644 --- a/src/run_commands.ts +++ b/src/run_commands.ts @@ -1,6 +1,6 @@ import { kill } from "../deps.ts"; import { getEnvVars } from "./env.ts"; -import { escape, isWindows, OneOrMore } from "./util.ts"; +import { escape, isWindows, notNull, OneOrMore } from "./util.ts"; import { log } from "./logger.ts"; import { Command, @@ -9,15 +9,27 @@ import { ParallelCommands, } from "./command.ts"; import { buildCommandString } from "./build_command_string.ts"; +import { ArgsForwardingMode } from "./run_script.ts"; const runningProcesses: Set = new Set(); -export async function runCommands( - commands: CompoundCommandItem[], - shell: string, - additionalArgs: string[], - cwd: string, -): Promise { +interface RunCommandsOptions { + shell: string; + cwd: string; + commands: CompoundCommandItem[]; + prefix?: string; + additionalArgs?: string[]; + argsForwardingMode?: ArgsForwardingMode; +} + +export async function runCommands({ + shell, + cwd, + commands, + prefix, + additionalArgs, + argsForwardingMode, +}: RunCommandsOptions): Promise { const _runCommands = async ( commands: OneOrMore, ): Promise => { @@ -30,7 +42,15 @@ export async function runCommands( if (isParallel(commands)) { return Promise.all(commands.pll.map((c) => _runCommands(c))); } - return runCommand(commands, shell, additionalArgs, cwd); + const command = commands as Command; + return runCommand({ + shell, + cwd, + command, + prefix, + additionalArgs, + argsForwardingMode, + }); } }; try { @@ -44,23 +64,42 @@ export async function runCommands( } } -async function runCommand( - command: Command, - shell: string, - additionalArgs: string[], - cwd: string, -): Promise { +type RunCommandOptions = Omit & { + command: Command; +}; + +async function runCommand({ + shell, + cwd, + command, + prefix, + additionalArgs, + argsForwardingMode, +}: RunCommandOptions): Promise { const cmd = buildCommandString(command); let runOptions: Deno.RunOptions = { - cmd: [shell, ...buildShellArgs(shell, cmd, additionalArgs)], + cmd: [ + shell, + ...buildShellArgs({ + shell, + command: cmd, + prefix, + additionalArgs, + argsForwardingMode, + }), + ], cwd, env: getEnvVars(command), }; log.debug( - `Running > ${cmd}${ - additionalArgs && additionalArgs.length > 0 - ? ` -- ${additionalArgs.join(" ")}` - : "" + `Running > ${ + [ + prefix, + cmd, + additionalArgs && additionalArgs.length > 0 + ? additionalArgs.join(" ") + : null, + ].filter(notNull).join(" ") }`, ); const process = Deno.run(runOptions); @@ -73,18 +112,34 @@ async function runCommand( } } -function buildShellArgs( - shell: string, - command: string, - additionalArgs: string[], -): string[] { - const fullCmd = additionalArgs.length < 1 - ? command - : `${command} ${ - additionalArgs.map((a) => `"${escape(a, '"')}"`).join(" ") - }`; +type BuildShellArgsOptions = Omit & { + command: string; +}; + +function buildShellArgs({ + shell, + command, + prefix, + additionalArgs, + argsForwardingMode, +}: BuildShellArgsOptions): string[] { + const cmd = [ + prefix, + command, + argsForwardingMode === ArgsForwardingMode.DIRECT && additionalArgs && + additionalArgs.length > 0 + ? additionalArgs.map((a) => `"${escape(a, '"')}"`).join(" ") + : null, + ].filter(notNull) + .join(" "); if (isWindows && /^(?:.*\\)?cmd(?:\.exe)?$/i.test(shell)) { - return ["/d", "/s", "/c", fullCmd]; + return ["/d", "/s", "/c", cmd]; } - return ["-c", fullCmd]; + return [ + "-c", + cmd, + ...(argsForwardingMode === ArgsForwardingMode.INDIRECT && additionalArgs + ? additionalArgs + : []), + ]; } diff --git a/src/run_script.ts b/src/run_script.ts index 079a1a5..3e2e734 100644 --- a/src/run_script.ts +++ b/src/run_script.ts @@ -7,10 +7,22 @@ import { resolveShell } from "./resolve_shell.ts"; import { runCommands } from "./run_commands.ts"; import { validateScript } from "./validate_script.ts"; +export enum ArgsForwardingMode { + DIRECT, + INDIRECT, +} + +export interface RunScriptOptions { + configData: ConfigData; + script: string; + prefix?: string; + additionalArgs?: string[]; + argsForwardingMode?: ArgsForwardingMode; +} + export async function runScript( - configData: ConfigData, - script: string, - additionalArgs: string[] = [], + { configData, script, prefix, additionalArgs, argsForwardingMode }: + RunScriptOptions, ) { const { cwd, config } = configData; if (script == null || script.length < 1) { @@ -23,7 +35,14 @@ export async function runScript( const commands = normalizeScript(scriptDef, rootConfig); const shell = resolveShell(); try { - await runCommands(commands, shell, additionalArgs, cwd); + await runCommands({ + shell, + cwd, + commands, + prefix, + additionalArgs, + argsForwardingMode, + }); } catch (e) { log.error(`Failed at the ${bold(script)} script`); Deno.exit(3); diff --git a/src/util.ts b/src/util.ts index fb2f473..1e0314f 100644 --- a/src/util.ts +++ b/src/util.ts @@ -43,3 +43,5 @@ export const isScriptObject = (script: any): script is ScriptObject => export const isParallelScripts = (script: any): script is ParallelScripts => script instanceof Object && "pll" in script; + +export const notNull = (o: any) => o != null;