checkmate-cli 0.4.1

Checkmate - API Testing Framework CLI
# Lifecycle Hooks

Run custom scripts at test lifecycle events.

## Overview

Hooks are executable scripts in `.checkmate/hooks/`:

```
.checkmate/
└── hooks/
    ├── pre_run     # Before tests start
    ├── post_run    # After tests complete
    ├── on_pass     # All tests passed
    └── on_fail     # Any tests failed
```

## Hook Events

| Hook | When | Typical Use |
|------|------|-------------|
| `pre_run` | Before tests start | Setup, notifications |
| `post_run` | After tests complete (always) | Cleanup, reporting |
| `on_pass` | All tests passed | Success notifications |
| `on_fail` | Any tests failed | Alerts, issue creation |

### Execution Order

1. `pre_run` (before)
2. Tests execute
3. `post_run` (always)
4. `on_pass` OR `on_fail` (based on results)

## Creating Hooks

### 1. Create the Script

```bash
# Create hook
cat > .checkmate/hooks/on_fail << 'EOF'
#!/bin/bash
echo "Tests failed!"
echo "Run: $CM_RUN_ID"
echo "Failed: $CM_FAILED / $CM_TOTAL"
EOF

# Make executable
chmod +x .checkmate/hooks/on_fail
```

### 2. Supported Formats

Hooks can be:
- Executable scripts (with shebang): `pre_run`
- Shell scripts: `pre_run.sh`, `pre_run.bash`
- Python scripts: `pre_run.py`
- Ruby scripts: `pre_run.rb`
- Node scripts: `pre_run.js`

## Environment Variables

Hooks receive context via environment:

| Variable | Description | Example |
|----------|-------------|---------|
| `CM_RUN_ID` | Run identifier | `cm-run-a3f` |
| `CM_SPEC` | Spec file name | `users.yaml` |
| `CM_TOTAL` | Total test count | `5` |
| `CM_PASSED` | Passed count | `4` |
| `CM_FAILED` | Failed count | `1` |
| `CM_ERRORS` | Error count | `0` |
| `CM_DURATION_MS` | Duration (ms) | `1234` |

### Availability by Hook

| Variable | pre_run | post_run | on_pass | on_fail |
|----------|---------|----------|---------|---------|
| `CM_SPEC` |||||
| `CM_RUN_ID` | - ||||
| `CM_TOTAL` | - ||||
| `CM_PASSED` | - ||||
| `CM_FAILED` | - ||||
| `CM_ERRORS` | - ||||
| `CM_DURATION_MS` | - ||||

## Examples

### Slack Notification on Failure

`.checkmate/hooks/on_fail`:
```bash
#!/bin/bash
curl -X POST "$SLACK_WEBHOOK" \
  -H 'Content-Type: application/json' \
  -d "{
    \"text\": \"API Tests Failed\",
    \"attachments\": [{
      \"color\": \"danger\",
      \"fields\": [
        {\"title\": \"Run\", \"value\": \"$CM_RUN_ID\", \"short\": true},
        {\"title\": \"Spec\", \"value\": \"$CM_SPEC\", \"short\": true},
        {\"title\": \"Results\", \"value\": \"$CM_PASSED/$CM_TOTAL passed\", \"short\": true},
        {\"title\": \"Duration\", \"value\": \"${CM_DURATION_MS}ms\", \"short\": true}
      ]
    }]
  }"
```

### Create GitHub Issue on Failure

`.checkmate/hooks/on_fail`:
```bash
#!/bin/bash
gh issue create \
  --title "API Test Failure: $CM_SPEC" \
  --body "Run: $CM_RUN_ID
Failed: $CM_FAILED / $CM_TOTAL tests
Duration: ${CM_DURATION_MS}ms

See \`cm show $CM_RUN_ID\` for details."
```

### Log to File

`.checkmate/hooks/post_run`:
```bash
#!/bin/bash
echo "$(date -Iseconds) $CM_RUN_ID $CM_SPEC $CM_PASSED/$CM_TOTAL" >> /var/log/checkmate.log
```

### Sound Alert (macOS)

`.checkmate/hooks/on_fail`:
```bash
#!/bin/bash
say "Tests failed. $CM_FAILED of $CM_TOTAL tests failed."
```

`.checkmate/hooks/on_pass`:
```bash
#!/bin/bash
say "All $CM_TOTAL tests passed."
```

### Python Hook

`.checkmate/hooks/on_fail.py`:
```python
#!/usr/bin/env python3
import os
import requests

run_id = os.environ.get('CM_RUN_ID')
failed = os.environ.get('CM_FAILED')
total = os.environ.get('CM_TOTAL')

# Send to monitoring service
requests.post('https://monitoring.example.com/alerts', json={
    'type': 'test_failure',
    'run_id': run_id,
    'failed': int(failed),
    'total': int(total)
})
```

### Setup/Teardown

`.checkmate/hooks/pre_run`:
```bash
#!/bin/bash
# Start test database
docker-compose up -d test-db
sleep 5
```

`.checkmate/hooks/post_run`:
```bash
#!/bin/bash
# Stop test database
docker-compose down test-db
```

## Execution Details

### Fire-and-Forget

Hooks run asynchronously (fire-and-forget):
- Test execution doesn't wait for hooks to complete
- Hook failures don't affect test results
- Hooks run in background

### Working Directory

Hooks run with working directory set to project root (parent of `.checkmate/`).

### Error Handling

Hook errors are reported as warnings but don't fail tests:

```
Warning: Failed to run hook on_fail: Permission denied
```

## Best Practices

### 1. Keep Hooks Fast

Hooks shouldn't slow down test execution:

```bash
# Good: Send async
curl -X POST "$WEBHOOK" &

# Avoid: Slow synchronous operation
sleep 10
```

### 2. Handle Missing Variables

Variables may not be set for all hooks:

```bash
#!/bin/bash
if [ -n "$CM_RUN_ID" ]; then
  echo "Run: $CM_RUN_ID"
fi
```

### 3. Use Absolute Paths

Working directory is project root:

```bash
#!/bin/bash
LOG_FILE="$HOME/.checkmate/test.log"
echo "$CM_RUN_ID" >> "$LOG_FILE"
```

### 4. Test Hooks Manually

```bash
# Simulate hook environment
CM_RUN_ID="test" CM_FAILED=1 CM_TOTAL=5 ./.checkmate/hooks/on_fail
```

## Troubleshooting

### Hook Not Running

1. Check file exists: `ls -la .checkmate/hooks/`
2. Check executable: `chmod +x .checkmate/hooks/on_fail`
3. Check shebang: First line should be `#!/bin/bash` or similar
4. Run manually to test

### Permission Denied

```bash
chmod +x .checkmate/hooks/on_fail
```

### Script Errors

Test hook manually:
```bash
CM_RUN_ID="test" ./.checkmate/hooks/on_fail
```

---

## See Also

- [CLI Reference]CLI_REFERENCE.md - Running tests
- [History]HISTORY.md - Tracking results