GitHub Web Hook ile Deployment

Git hosting olarak Github kullanılan projelerde, Github’a gönderilen her yeni commit’de bir web adresinin tetiklenmesini sağlayabilirsiniz. Service Hooks menüsü altında yer alan WebHook URLs sayfasından, kaynak kodda değişiklik olduğu zaman, önceden tanımlanmış adres(ler)e POST methoduyla, güncelleme bilgilerini içeren JSON-encoded data ile beraber istek gönderilir. Burada örnek içeriğini bulacağınız payload bilgisine bakarak isteğin Github’dan gelip gelmediğini kontrol edebiliriz.

Github web hook için hazırladığım örnek bir deploy script’i:

<?php

// --------------------------------------------------------------
// Deployment ayarları
// --------------------------------------------------------------

ini_set('display_errors', 1);
error_reporting(E_ALL);
set_time_limit(0);

// hangi branch ile production güncellensin?
$productionBranchName = 'master';

// Github hook harici, adres satırından çalıştırmak için
// izin verilen IP adresleri.
$validIps = array(
    '1.2.3.4',
);

// güncelleme yetkisi olan kullanıcıların Github email adresleri
$validPusherEmails = array(
    'name@company.com',
);

// uygulama root'u
$rootPath = realpath( dirname(__FILE__) . '/../') . '/';

// hatalı istek olursa
function forbiddenRequest() {
    header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
    header("Status: 404 Not Found");
    echo '404 Not Found';
    exit;
}

// --------------------------------------------------------------
// Gelen isteği kontrol edelim
// --------------------------------------------------------------

if ( !in_array($_SERVER['REMOTE_ADDR'], $validIps) ) {
    
    // IP adresi izin verilen dışında.
    // Github'dan gelip gelmediğine bakalım.
    
    if ( !isset($_SERVER['HTTP_X_GITHUB_EVENT']) || 
         $_SERVER['HTTP_X_GITHUB_EVENT'] != 'push' || 
         !isset($_POST['payload']) 
       ) {
        
        forbiddenRequest();
    }

    $data = json_decode($_POST['payload'], true);

    if ( !is_array($data) || 
         !isset($data['repository']['id']) || 
         !isset($data['pusher']['email']) ||
         !in_array($data['pusher']['email'], $validPusherEmails)
       ) {

        forbiddenRequest();
    }

    // sadece production reposuna push gelmişse güncellesin
    if ( "refs/heads/$productionBranchName" != $data['ref'] ) {
        exit;
    }
}

// --------------------------------------------------------------
// Deploy
// --------------------------------------------------------------

$command  = '';

// info
$command .= 'echo "===== Deploying to live site =====\n";';
$command .= 'echo "Current path: $PWD\n";';
$command .= 'echo "Current user:";whoami;echo "\n"';

// git pull
$command .= 'echo "===== Pull from github ('.$productionBranchName.')  =====\n";';
$command .= "cd {$rootPath};git reset --hard HEAD;git clean -f -d;git pull origin {$productionBranchName} 2>&1;";

// buraya, cache dosyalarının temizlenmesi, 
// db migration gibi komutlarınızı ekleyebilirsiniz.

$command .= 'echo "===== Done =====";';

$output = shell_exec($command . ' 2>&1');
echo "<pre>$output</pre>";

// output'u mail ile kendinize gonderebilirsiniz.