captainhookphp / captainhook

CaptainHook is a very flexible git hook manager for software developers that makes sharing git hooks with your team a breeze.
http://captainhook.info
MIT License
1.01k stars 87 forks source link

enable user input for prepush #236

Closed labya closed 8 months ago

labya commented 9 months ago

i want to have a prompt to confirm the push on a branch

sebastianfeldmann commented 9 months ago

I'm not sure you can receive input via stdIn (which pre-push does) and still ask for user input. I remember trying this and not getting it to work. That's why I only allow user input for hooks that do not receive data via stdIn. Have you actually tried running it with your changes?

labya commented 9 months ago

hi,

yeah i tried and it's work :)

Here my captainhook.json :

"pre-push": {
        "enabled": true,
        "actions": [
          {
            "action": "\\scripts\\CaptainHook\\HookPrePush"
          }
        ]
    },

And my class HookPrePush.php

<?php

namespace scripts\CaptainHook;

use CaptainHook\App\Config;
use CaptainHook\App\Config\Action as ConfigAction;
use CaptainHook\App\Console\IO;
use CaptainHook\App\Hook\Action;
use SebastianFeldmann\Git\Repository;

/**
 *
 */
class HookPrePush implements Action {

  /**
   * Execute the action.
   *
   * @param  \CaptainHook\App\Config           $config
   * @param  \CaptainHook\App\Console\IO       $console_io
   * @param  \SebastianFeldmann\Git\Repository $repository
   * @param  \CaptainHook\App\Config\Action    $action
   * @return void
   * @throws \Exception
   */
  public function execute(
    Config $config,
    IO $console_io,
    Repository $repository,
    ConfigAction $action
  ) : void {
    $show_branch = sprintf(
      'git -C %s %s',
      $repository->getRoot(),
      'branch --show-current'
    );
    $branch = trim(shell_exec($show_branch));
    if ($branch === 'master') {
      $response = $console_io
        ->ask('Are you sure you want to push to ' . $branch . '? (y/n): ', 'n');
      if (strtolower(trim($response)) !== 'y') {
        throw new \Exception('Push aborted.');
      }
    }
  }

}

with this PR, the file .git/hooks/pre-push are now :

#!/bin/sh

# installed by CaptainHook 5.21.2

INTERACTIVE="--no-interaction"
if [ -t 1 ]; then
    # If we're in a terminal, redirect stdout and stderr to /dev/tty and
    # read stdin from /dev/tty. Allow interactive mode for CaptainHook.
    exec >/dev/tty 2>/dev/tty </dev/tty
    INTERACTIVE=""
fi

vendor/bin/captainhook $INTERACTIVE --configuration=captainhook.json --bootstrap=vendor/autoload.php hook:pre-push "$@"

it would be nice to have a parameter to populate the $hooksAllowingUserInput array via captainhook.json

sebastianfeldmann commented 9 months ago

Ah, I see, you are not reading any data from stdIn before. Some conditions read some data from stdIn for pre-push.

Thanks for the example I will try this in combination with some code that requires the stdIn stuff to work as well.

sebastianfeldmann commented 9 months ago

So far I could not get it to work to read from stdIn and tty. Since it doesn't seem to be possible to change the stdIn file descriptor from PHP.

I'm thinking of allowing user input and how to reliably do it for a while now.

So here is what I'm going to do. First I will not merge this pull request, since it would break other functionality. But I will make some changes that should allow user input for all hooks.

For this to work I have to use the hook script to actually read the default git stdIn and pass it to CaptainHook as argument or option so the Cap'n can always use the tty.

This will not work with the pure PHP installation method were no shell script is used to execute the Captain. I would hope that no one is still using this variant, it's some very old stuff from the early days. Nevertheless I will still invest some more time to make the impact for people using it as pain free as possible.

So it will take maybe a day or two more to get something released that could solve your issue.

sebastianfeldmann commented 8 months ago

I just released version 5.22.0

It contains an Action to prompt the user for confirmation. You can configure it like this:

            {
                "action": "\\CaptainHook\\App\\Hook\\UserInput\\AskConfirmation",
                "options": {
                    "message": "Do you really want it? [yes|no]",
                    "default": true
                },
                "config": {
                    "label": "User confirmation!"
                }
            }

User input should be possible for all hooks now as long as you use run-mode shell or docker. In run-mode php user input does not work for pre-push and post-rewrite because of the stdIn handling if git.