Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GitHub for Windows Pre-Commit Hook

Tags:

git

github

We have a development team that is using a 50/50 split of GitHub for windows and Bash shell for their Git management.

We have implemented a pre-commit hook (designed to run unit tests and fail the commit when tests fail). As a simplified version I have attached a cut down version below which demos our issue.

#!/bin/sh
exit 1

If we attempt a commit from the bash shell, the commit as expected fails. However if we perform the same commit from the GitHub for windows application it is successfully committed to the local repo.

So Does anyone know how we can get the same functionality from GitHub application? Unfortunately we can't move the users off the application, and its now an obvious hole.

Thanks for your help.

like image 933
Steve Goodman Avatar asked Sep 13 '12 15:09

Steve Goodman


People also ask

Do git hooks work on Windows?

However, Git on Windows is able to recognize the shebang first line. Therefore, we add a shebang line in a Git hook script on Windows just as we do on Linux. Below are two Git commit-msg hooks that run on Linux and Windows respectively. If you are using Git for Windows, the bash script also works on Windows.

How do you pre-commit a hook?

Open a terminal window by using option + T in GitKraken Client. Once the terminal windows is open, change directory to . git/hooks . Then use the command chmod +x pre-commit to make the pre-commit file executable.

What are pre-commit hooks github?

The pre-commit hook is run first, before you even type in a commit message. It's used to inspect the snapshot that's about to be committed, to see if you've forgotten something, to make sure tests run, or to examine whatever you need to inspect in the code.


2 Answers

Sorry to be the bearer of bad news, but GitHub for Windows doesn't support pre-commit hooks, since it uses libgit2 to commit.

like image 62
Ana Betts Avatar answered Sep 28 '22 09:09

Ana Betts


Using Git shell you can have commit hooks. I got some commit hooks working with PowerShell. I found a powerShell script that did lint that I expanded to run phpunit and phpcs (paths are hard coded so you will need to adjust):

pre Commit File:

#!/bin/sh
echo 
exec powershell.exe -ExecutionPolicy RemoteSigned -File '.\.git\hooks\pre-commit-hook.ps1'
exit

pre-commit.ps1 file:

###############################################################################
#
# PHP Syntax Check for Git pre-commit hook for Windows PowerShell
#
# Author: Vojtech Kusy <[email protected]>
# Author: Chuck "MANCHUCK" Reeves <[email protected]>
#
###############################################################################

### INSTRUCTIONS ###

# Place the code to file "pre-commit" (no extension) and add it to the one of 
# the following locations:
# 1) Repository hooks folder - C:\Path\To\Repository\.git\hooks
# 2) User profile template   - C:\Users\<USER>\.git\templates\hooks 
# 3) Global shared templates - C:\Program Files (x86)\Git\share\git-core\templates\hooks
# 
# The hooks from user profile or from shared templates are copied from there
# each time you create or clone new repository.

### SETTINGS ###

# Path to the php.exe
$php_exe = "C:\php\php.exe";

# Path to the phpcs
$php_cs = "C:\Includes\PEAR\phpcs.bat";

# Path to the phpunit
$php_unit = "C:\Includes\PEAR\phpunit.bat";

# Path to the phpunit bootstrap file
$bootstrap = "tests\bootstrap.php";

# Flag, if set to 1 require test file to exist, set to 0 to disable
$requireTest = 1;

# Extensions of the PHP files 
$php_ext = "php|phtml"

# Flag, if set to 1 git will unstage all files with errors, set to 0 to disable
$unstage_on_error = 0;

### FUNCTIONS ###

function php_syntax_check {
    param([string]$php_bin, [string]$extensions, [int]$reset) 

    $err_counter = 0;

    write-host "Pre-commit PHP syntax check:" -foregroundcolor "white" -backgroundcolor "black"

    git diff-index --name-only --cached HEAD -- | foreach {             
        if ($_ -match ".*\.($extensions)$") {
            $file = $matches[0];
            $errors = & $php_bin -l $file   
            $testFileExists = (Test-Path $file -PathType Leaf)
            write-host $file ": "  -foregroundcolor "gray"  -backgroundcolor "black" -NoNewline
            if ($testFileExists) {
                if ($errors -match "No syntax errors detected in $file") {
                    write-host "OK!" -foregroundcolor "green" -backgroundcolor "black"
                }
                else {              
                    write-host "ERROR! " $errors -foregroundcolor "red" -backgroundcolor "black"
                    if ($reset) {
                        git reset -q HEAD $file
                        write-host "Unstaging ..." -foregroundcolor "magenta" -backgroundcolor "black"
                    }
                    $err_counter++
                }
            } else {
                write-host "OK! (file deleted)" -foregroundcolor "green" -backgroundcolor "black"
            }
        }
    }

    if ($err_counter -gt 0) {
        write-host "Some File(s) have syntax errors. Please fix then commit" -foregroundcolor "red" -backgroundcolor "black"
        exit 1
    }    
}

function php_cs_check {
    param([string]$php_cs, [string]$extensions, [int]$reset) 

    $err_counter = 0;

    write-host "Pre-commit PHP codesniffer check:" -foregroundcolor "white" -backgroundcolor "black"

    git diff-index --name-only --cached HEAD -- | foreach {     
        if ($_ -match ".*\.($extensions)$") {
            $file = $matches[0];

            write-host $file ": "  -foregroundcolor "gray"  -backgroundcolor "black" -NoNewline
            if ($file -match "tests\/") {
                write-host "PASSED! (test file)" -foregroundcolor "green" -backgroundcolor "black"
            } else {
                $errors = & $php_cs --standard=Zend $file           

                if ($LastExitCode) {
                    write-host "FAILED! (contains errors)"  -foregroundcolor "red" -backgroundcolor "black"
                    if ($reset) {
                        git reset -q HEAD $file
                        write-host "Unstaging ..." -foregroundcolor "magenta" -backgroundcolor "black"
                    }
                    $err_counter++
                } else {                
                    write-host "PASSED!" -foregroundcolor "green" -backgroundcolor "black"
                }
            }
        }
    }

    if ($err_counter -gt 0) {
        write-host "Some File(s) are not following proper codeing standards. Please fix then commit" -foregroundcolor "red" -backgroundcolor "black"
        exit 1
    }    
}

function php_unit_check {
    param([string]$php_unit, [string]$bootstrap, [string]$extensions, [int]$reset, [int]$requireTest) 

    $err_counter = 0;

    write-host "Pre-commit PHP unit check:" -foregroundcolor "white" -backgroundcolor "black"

    git diff-index --name-only --cached HEAD -- | foreach {     
        if ($_ -match ".*\.($extensions)$") {
            $file = $matches[0];

            write-host $file ": "  -foregroundcolor "gray"  -backgroundcolor "black" -NoNewline
            if ($file -match "tests\/") {
                write-host "SKIPPED! (test file)" -foregroundcolor "green" -backgroundcolor "black"
            } elseif ($file -match ".*Bootstrap.php") {
                write-host "SKIPPED! (bootstrap file)" -foregroundcolor "green" -backgroundcolor "black"
            } elseif ($file -match "([application|library\\NDX].*)(.($extensions))$") {

                $testFile = 'tests/' + $matches[1] + "Test.php";
                $testFileExists = (Test-Path $testFile -PathType Leaf)

                if ($testFileExists) {
                    $errors = & $php_unit --bootstrap $bootstrap $testFile
                    if ($LastExitCode) {
                        write-host "FAILED! (" $testFile ")"  -foregroundcolor "red" -backgroundcolor "black"
                        if ($reset) {
                            git reset -q HEAD $file
                            write-host "Unstaging ..." -foregroundcolor "magenta" -backgroundcolor "black"
                        }
                        $err_counter++
                    } else {
                        write-host "PASSED!" -foregroundcolor "green" -backgroundcolor "black"

                    }
                } elseif($requireTest) {
                    write-host "FAILED! Test file Not found: (" $testFile ")"  -foregroundcolor "red" -backgroundcolor "black"
                    if ($reset) {
                        git reset -q HEAD $file
                        write-host "Unstaging ..." -foregroundcolor "magenta" -backgroundcolor "black"
                    }
                    $err_counter++
                } else {
                    write-host "PASSED! (Test file not found and not required)" -foregroundcolor "darkGreen" -backgroundcolor "black"
                }
            } else {
                write-host "IGNORED!" -foregroundcolor "darkGreen" -backgroundcolor "black"
            }
        }
    }

    if ($err_counter -gt 0) {
        write-host "Some File(s) failed unit testing. Please fix then commit" -foregroundcolor "red" -backgroundcolor "black"
        exit 1
    }    
}
### MAIN ###

php_syntax_check $php_exe "php|phtml" $unstage_on_error
write-host
php_cs_check $php_cs "php" $unstage_on_error
write-host
php_unit_check $php_unit $bootstrap "php" $unstage_on_error $requireTest
like image 32
MANCHUCK Avatar answered Sep 28 '22 08:09

MANCHUCK