
# Konksud

Git konksud on täidetavad skriptid asukohas `.git/hooks/`, mis käivituvad git toimingute kindlates punktides. Pitmaster tuvastab ja käivitab konksud, kasutades PHP protsessihaldust (`proc_open`).

## Konksud käivituvad vaikimisi

Hoidla toimingud käivitavad automaatselt konksud, mis on loetletud jaotises [Konksud Pitmaster käivitab](#hooks-pitmaster-runs). Nende väljalülitamiseks hoidla käepideme puhul edastage selle avamisel suvandid:

```php
use Pitmaster\Pitmaster;

// Skip .git/hooks scripts for this handle
$repo = Pitmaster::open('/path/to/project', ['hooks' => false]);

// Start no processes at all: hooks, the fsmonitor hook, clone/fetch/push, and SSH are disabled
$repo = Pitmaster::open('/path/to/project', Pitmaster::processFreeOptions());

$repo->hooksEnabled();      // false
$repo->processesEnabled();  // false for the second handle
```

`Pitmaster::init()` ja `Pitmaster::clone()` aktsepteerivad samu suvandeid. Konksu käivitamiseks on vaja `proc_open()`; hostides, kus see on keelatud, avage hoidlad suvandiga `['hooks' => false]`. CLI avab hoidla alati konksud lubatuna.

Pitmaster otsib konkse ainult asukohast `<gitDir>/hooks`. See eirab asukohta `core.hooksPath` ning lingitud tööpuus otsib asukohast `.git/worktrees/<name>/hooks`, mistõttu jagatud `.git/hooks` skriptid seal ei käivitu ([#12](https://github.com/inline0/pitmaster/issues/12)).

`HookRunner`, mida kirjeldatakse allpool, eirab neid suvandeid: otse väljakutsumine käivitab konksu alati.

## HookRunner

```php
use Pitmaster\Hooks\HookRunner;

$hooks = new HookRunner($repo->gitDir());
```

## Kontrollige, kas konks on olemas

```php
if ($hooks->exists('pre-commit')) {
    echo "pre-commit hook is installed\n";
}
```

Konks on olemas, kui fail asukohas `.git/hooks/<name>` on olemas ja käivitatav.

## Konksu käivitamine

```php
$result = $hooks->run('pre-commit');

echo $result['exitCode'];  // 0 = success
echo $result['stdout'];    // Hook's standard output
echo $result['stderr'];    // Hook's standard error
```

### Argumentidega

```php
$result = $hooks->run('commit-msg', ['/path/to/COMMIT_EDITMSG']);
```

### standardse sisendiga

```php
$result = $hooks->run('pre-push', ['origin', 'https://github.com/user/repo.git'], $stdinData);
```

Konks `pre-push` saab viiteavet standardse sisendi kaudu.

### Edu kontrollimine

```php
if ($hooks->runAndCheck('pre-commit')) {
    // Hook passed (exit code 0), proceed with commit
} else {
    // Hook rejected the operation
}
```

`runAndCheck()` on abifunktsioon, mis käivitab konksu ja tagastab `true`, kui väljumiskood on 0. Kui konksu pole olemas, tagastab see `true` (konksu puudumine tähendab vastuväidete puudumist).

## Paigaldatud konksude loetlemine

```php
$installed = $hooks->listHooks();
// ['pre-commit', 'commit-msg', 'post-checkout']
```

Loetleb kõik käivitatavad failid asukohas `.git/hooks/` (välja arvatud `.sample` failid).

`run()` tagastab puuduva või mittekäivitatava konksu korral väljumiskoodi 0 ja tühja väljundi. Kui protsessi ei saa käivitada, tagastab see väljumiskoodi 1 ning väljastab standardveavoo kaudu `Failed to start hook`.

## Konksu paigaldamine

```php
$hooks->install('pre-commit', "#!/bin/bash\nphp vendor/bin/phpcs --standard=PSR12 .\n");
```

Kirjutab skripti sisu asukohta `.git/hooks/<name>` ja määrab sellele käivitusõiguse (`chmod 0755`).

```php
// Install a PHP hook
$hooks->install('pre-commit', <<<'HOOK'
#!/usr/bin/env php
<?php
// Run static analysis before commit
$output = [];
$returnCode = 0;
exec('php vendor/bin/phpstan analyse --no-progress 2>&1', $output, $returnCode);

if ($returnCode !== 0) {
    echo "PHPStan found errors:\n";
    echo implode("\n", $output) . "\n";
    exit(1);
}
HOOK);
```

## Konksud, mida Pitmaster käivitab

`HookRunner` saab käivitada nime järgi mis tahes konksu. `Repository` käivitab automaatselt järgmised konksud:

| Konks | Käivitaja | Argumendid | Kas saab katkestada? |
|------|--------|-----------|-----------|
| `pre-commit` | `commit()` | puuduvad | Jah (nullist erinev väljumiskood) |
| `prepare-commit-msg` | `commit()` | sõnumifail, seejärel `message` (või `merge` ühinemise lõpetamisel) | Jah |
| `commit-msg` | `commit()` | sõnumifail (`.git/COMMIT_EDITMSG`); faili muudatused võetakse kasutusele | Jah (nullist erinev väljumiskood) |
| `post-commit` | `commit()` | puuduvad | Ei (teavitav) |
| `pre-rebase` | `rebase()` | ülesvoolu versioon | Jah |
| `post-checkout` | `checkout()` | vana HEAD, uus HEAD, `1` | Ei (teavitav) |
| `post-merge` | `merge()`, `mergeOctopus()`, `mergeContinue()` | `0` | Ei (teavitav) |
| `pre-push` | `push()` ja selle variandid | kaugserveri nimi, URL; viiteread standardse sisendi kaudu | Jah (nullist erinev väljumiskood) |

Ebaõnnestunud konks paneb toimingu veaga `RuntimeException('<name> hook failed')` lõppema; konksu väljundit ei lisata. Muudatuse kinnitamise konksud käivituvad ainult `commit()` kaudu: `merge()` loodud ühinemiskinnitused neid ei käivita. `post-checkout` ei käivitu toimingute `addWorktree()`, `reset()` ega `restore()` puhul.

Serveripoolsed konksud (`pre-receive`, `update`, `post-receive`, `post-update`), `pre-auto-gc` ja `post-rewrite` ei käivitu kunagi automaatselt.

## Konksu keskkond

Kui Pitmaster konksu käivitab, edastab see järgmise keskkonna:

```php
$env = [
    'GIT_DIR' => $this->gitDir,
    'GIT_WORK_TREE' => dirname($this->gitDir),
];
```

Need on ainsad muutujad, mille konks saab: `PATH`, `HOME` ja kõik muud PHP protsessi muutujad ei kandu edasi ([#13](https://github.com/inline0/pitmaster/issues/13)). Kasutage konksuskriptides absoluutseid teid või määrake skripti sees `PATH`; `#!/usr/bin/env php` shebang leiab tõlgendajad ainult süsteemi vaikeotsinguteelt.

Konks käivitub asukohas `dirname($gitDir)`, mis on tavalise `.git` kataloogi tööpuu.

## Konksuskripti vorming

Konkse saab kirjutada mis tahes keeles. Esimesel real peab olema shebang:

```bash
#!/bin/bash
# Bash hook
```

```php
#!/usr/bin/env php
<?php
// PHP hook
```

```python
#!/usr/bin/env python3
# Python hook
```

## Näide: eelkontroll Pitmaster-iga

`commit()` käivitab juba `pre-commit`, `prepare-commit-msg`, `commit-msg` ja `post-commit`, seega peab rakenduse kood tegelema ainult tõrke käsitlemisega:

```php
try {
    $commitId = $repo->commit('Add feature');
} catch (\RuntimeException $e) {
    echo $e->getMessage(); // "pre-commit hook failed"
}
```

Kutsuge `HookRunner` ise välja ainult käepidemel, mis on avatud suvandiga `['hooks' => false]`, või nende konksude puhul, mida Pitmaster ei käivita.

## Näidiskonksud

Git lähtestab hoidlad koos `.sample` konksufailidega; `Pitmaster::init()` loob tühja kataloogi `hooks/`. Pitmaster `listHooks()` välistab `.sample` failid:

```
.git/hooks/
  pre-commit.sample       (excluded from listHooks)
  commit-msg.sample       (excluded from listHooks)
  pre-commit              (included - installed by user)
```
