git hook proxy

In my previous blogpost I was talking about the idea of having proxy which extracts and executes hooks from the repo.

Initially proxy was written for server-side hooks, but later I found it useful to be used for client-side hooks as well.

After enabling this idea on production I’ve immediately faced with some minor issues and I would like to show the final versions.

Example of client-side hook – local-repo-path\.git\hooks\commit-msg

#!/bin/sh
#
commitMessagePath=$1
psCommand=".\\.git\\hooks\\HookProxy.ps1 -Branch origin/master -HookName commit-msg -Arguments \"-CommitMessagePath\", \"$commitMessagePath\""
c:/windows/system32/WindowsPowerShell/v1.0/PowerShell.exe -Sta -ExecutionPolicy RemoteSigned -NoProfile -Command "$psCommand"

Example of server-side hook – server-repo-path\hooks\pre-receive

#!/bin/sh
#
while read oldRef newRef refName
do
    psCommand=".\\hooks\\HookProxy.ps1 -Branch master -HookName pre-receive -Arguments \"-OldRef\", \"$oldRef\", \"-NewRef\", \"$newRef\", \"-RefName\", \"$refName\""
    c:/windows/system32/WindowsPowerShell/v1.0/PowerShell.exe -Sta -ExecutionPolicy RemoteSigned -NoProfile -Command "$psCommand"

    exitCode=$?

    if [ $exitCode != 0 ]
    then
        exit $exitCode
    fi
done

Final version of HookProxy.ps1 – local-repo-path\.git\hooks\HookProxy.ps1 and server-repo-path\hooks\HookProxy.ps1

#requires -version 2.0

[CmdletBinding()]
param
(
    [string] $Branch,
    [string] $HookName,
    [object[]] $Arguments
)

$script:ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest
function PSScriptRoot { $MyInvocation.ScriptName | Split-Path }

Trap { throw $_ }

function Main
{
    $tempDir = "temp_$([Guid]::NewGuid())"
    New-Item -Path $tempDir -ItemType Directory | Out-Null

    try
    {
        Git-CheckoutFile -Branch $Branch -RelativeFilePath tools\GitHooks -DestinationFolder $tempDir

        & "$PSHOME\PowerShell.exe" -Sta -ExecutionPolicy RemoteSigned -NoProfile -Command "$tempDir\GitHooks\$HookName.ps1 $Arguments"
    }
    finally
    {
        Remove-Item -Path $tempDir -Recurse -Force
    }

}

function Git-CheckoutFile
{
    param
    (
        [string] $Branch,
        [string] $RelativeFilePath,
        [string] $DestinationFolder
    )

    if ($RelativeFilePath -eq ".")
    {
        $RelativeFilePath = "*"
    }

    $RelativeFilePath = $RelativeFilePath -replace "\\", "/"

    $tempDir = "temp_$([Guid]::NewGuid())"
    New-Item -Path $tempDir -ItemType Directory | Out-Null

    git archive $Branch $RelativeFilePath --output "$tempDir/__temp.tar"
    tar -xf "$tempDir/__temp.tar" -C $tempDir
    Remove-Item "$tempDir\__temp.tar"

    if (-not (Test-Path $DestinationFolder))
    {
        New-Item -Path $DestinationFolder -ItemType Directory | Out-Null
    }

    Copy-Item -Path "$tempDir/$RelativeFilePath" -Destination $DestinationFolder -Recurse

    Remove-Item -Path $tempDir -Recurse -Force
}

Main

I have to run to call a separate PowerShell process in line #26 because one of my hooks internally used Import-Module Some.dll, and as we know as soon as assembly is loaded it could be deleted only when corresponding AppDomain is closed. Without this extra PowerShell process, proxy fails at line #30 because corresponding dll file is locked.

Advertisements

About mnaoumov

Senior .NET Developer in Readify
This entry was posted in Uncategorized and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s