Git hooks
Kilka prostych hooks, które przydadzą się dla osób pracujących z git/gitlab oraz bugzilla i redmine. Dzięki nim można zautomatyzować trochę nasze procesy commit oraz push. A co najważniejsze: wszystko to możemy napisać w php.
Nazwa bugu z bugzilli w komentarzu
Załóżmy, że pracujemy z bugzilla. Gdy pracujemy nad jakimś błędem z bugzilli to tworzymy branch o nazwie bug/12345 gdzie 12345 jest numerem błędu w bugzilla. Teraz komitując coś w naszym branchu chcemy by komentarz zawierał nazwe błędu z bugzilla by łatwo mozna było zidentyfikować błąd nad którym pracowalismy.
W tym celu dodajemy hook do naszego projektu git ./git/hooks/prepare-commit-msg o następującej treści:
#!/usr/bin/php
<?php
define('BUG_USER', 'username'); //nasz user do bugzilla
define('BUG_PASS', 'password'); //nasze haslo do bugzilla
define('BUG_URL', 'http://link.to.your.bugzilla/'); //adres do naszego projektu bugzilla
function writeMessage($bugNumber, $oldMessage, $bugSummary = '') {
global $argv;
$message = $bugNumber;
if ($bugSummary) {
$message .= ': ' . $bugSummary;
}
if ($oldMessage) {
$message .= ': ' . $oldMessage;
}
file_put_contents($argv[1], $message);
}
$message = trim(file_get_contents($argv[1]));
$currentBranch = trim(exec('git symbolic-ref --short HEAD'));
$ar = explode('/', $currentBranch);
//sprawdzamy czy nazwa branch to bug/bugnumber
if (count($ar) !== 2 || $ar[0] !== 'bug' || !is_numeric($ar[1])){
exit;
}
$bugNumber = $ar[1];
//logujemy się do naszej bugzilli
$loginResponse = json_decode(file_get_contents(BUG_URL . 'rest/login?login=' . BUG_USER . '&password=' . BUG_PASS), true);
if (empty($loginResponse['token'])){
writeMessage($bugNumber, $message);
exit;
}
$token = $loginResponse['token'];
//pobieramy info o błędzie z bugzilli
$bugResponse = json_decode(file_get_contents(BUG_URL . 'rest/bug/' .$bugNumber. '?token=' . $token), true);
if (empty($bugResponse['bugs'])){
writeMessage($bugNumber, $message);
exit;
}
//dodajemy nazwe błędu do naszego komentarza w commit
writeMessage($bugNumber, $message, $bugResponse['bugs'][0]['summary']);
Po stworzeniu powyższego hook gdy odpalimy w commit w naszym branchu bug/12345
git commit -m ''
Zostanie zrobiony commit z komentarzem: 12345: bug summary. Zaś gdy chcemy mieć też własny komentarz:
git commit -m 'nasz komentarz'
Zostanie zrobiony commit z komentarzem: 12345: bug summary: nasz komentarz.
Gitlab do bugzilla
No dobra, nadal pracujemy z bugzilla ale teraz jeszcze mamy do dyspozycji gitlab. Teraz gdy ktoś wrzuci jakiś branch do gitlab to chcielibyśmy mieć info o tym w naszym bugu w bugzilla. W tym celu na serwerze gdzie jest gitlab wrzucamy następujący hook /var/opt/gitlab/git-data/repositories/GITLAB_PROJECT.git/custom_hooks/post-receive o następującej treści:
#!/usr/bin/php
<?php
function getAuthor($revision) {
//tablica z userami w bugzilla
//można tu ustawić tylko jednego domyślnego usera i wszystkie komentarze w bugzilla będą dodawane przez tego usera
$authors = [
'author1' => 'password1',
'author2' => 'password2',
];
//Pobranie email z rewizji
$text = trim(exec("git show $revision | grep 'Author'"));
preg_match('/<(.*?)>/', $text, $matches);
$email = $matches[1];
$key = isset($authors[$email]) ? $email : key($authors);
return [
'email' => $email,
'credentials' => ['user' => $key, 'password' => $authors[$key]]
];
}
define('BUG_URL', 'http://link.to.your.bugzilla/'); //adres do naszej bugzilli
define('GITLAB_URL', 'http://link.to.your.gitlab/'); //adres do naszego gitlab
$stdin = fopen('php://stdin', 'r');
$line = trim(fgets(STDIN));
$ar = explode(' ', $line);
if (count($ar) !== 3) {
exit;
}
//pobranie nazwy projektu
$path = exec('echo $PWD');
$search = [
'/var/opt/gitlab/git-data/repositories/',
'.git'
];
$projectName = str_replace($search, '', $path);
$revision = $ar[1];
if ($revision === '0000000000000000000000000000000000000000') { //gdy usuniemy branch po jego zmergowaniu do master to takie kwiatki możemy mieć
exit;
}
//pobranie nazwy brancha
$branchName = str_replace('refs/heads/', '', $ar[2]);
$ar = explode('/', $branchName);
//sprawdzenie czy branch ma nazwe bug/bugnumber
if (count($ar) !== 2 || $ar[0] !== 'bug' || !is_numeric($ar[1])){
exit;
}
$bugNumber = $ar[1];
$author = getAuthor($revision);
//zalogowanie do bugzilli
$loginResponse = json_decode(file_get_contents(BUG_URL . 'rest/login?login=' . $author['credentials']['user'] . '&password=' . $author['credentials']['password']), true);
if (empty($loginResponse['token'])){
exit;
}
$token = $loginResponse['token'];
$comment = "Code change by $author[email]:
Latest change
" . GITLAB_URL . "{$projectName}/commit/$revision";
//dodanie komentarza do błędu w bugzilli
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, BUG_URL . 'rest/bug/' .$bugNumber. '/comment?token=' . $token);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true );
curl_setopt($curl, CURLOPT_POSTFIELDS, [
'comment' => $comment,
'is_private' => false,
'is_markdown' => false,
]);
curl_exec($curl);
curl_close($curl);
Po stworzeniu tego hook, gdy wrzucimy jakiś branch bug/12345 do gitlab, w danym bug w bugzilli zostanie dodany komentarz z linkiem do naszego wrzutu w gitlab. Dzięki temu można bardzo łatwo śledzić w bugzilla wszelkie zmiany dla danych błędów.
Hash redmine w komentarzu
Teraz coś dla osób pracujących z redmine. Pracując nad jakimś zadaniem z redminem chcemy, by razem z komitem szedł hash z numerem zadania z redmine, dzięki czemu w redmine będziemy mogli śledzić zmiany w zadaniach. W tym celu tworzymy hook w naszym projekcie git ./git/hooks/prepare-commit-msg o treści:
#!/usr/bin/php
<?php
function writeMessage($bugNumber, $oldMessage) {
global $argv;
$message = $oldMessage;
if ($bugNumber) {
$message .= ' refs #' . $bugNumber;
}
file_put_contents($argv[1], $message);
}
$message = trim(file_get_contents($argv[1]));
$currentBranch = trim(exec('git symbolic-ref --short HEAD'));
$ar = explode('/', $currentBranch);
$bugNumber = end($ar);
//sprawdzenie czy ostatni człon nazwy brancha to numer
if (!is_numeric($bugNumber)){
exit;
}
writeMessage($bugNumber, $message);
Teraz gdy już mamy hook i gdy zamierzamy pracować nad jakimś zadaniem z redmine tworzymy branch o nazwie np. feature/12345 - ważne by ostatnim członem był numer zadania w redmine. Gdy będziemy robić commit na naszym branchu zostanie dodany na koniec naszego komentarza hash z numerem zadania z redmine co umożliwi nam śledzenie zmian z poziomu redmine.
Podsumowanie
Wszystkie opisane tu hooks możecie znaleźć na moim github
ps: Pamiętajcie, by wszystkie pliki hooks tworzyć jako pliki wykonywalne.