omgkit 2.23.0 → 2.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/omgkit.js +5 -4
- package/lib/cli.js +62 -32
- package/package.json +2 -2
- package/plugin/commands/hooks/run.md +144 -0
- package/plugin/commands/hooks/setup.md +174 -0
- package/plugin/commands/workflow/init.md +143 -0
- package/plugin/commands/workflow/status.md +126 -0
- package/plugin/commands/workflow/trunk-based.md +175 -0
- package/plugin/registry.yaml +16 -3
- package/plugin/skills/devops/git-hooks/SKILL.md +526 -0
- package/plugin/skills/devops/workflow-config/SKILL.md +581 -0
- package/plugin/workflows/git/trunk-based.md +447 -0
- package/templates/omgkit/workflow-gitflow.yaml +128 -0
- package/templates/omgkit/workflow-github.yaml +100 -0
- package/templates/omgkit/workflow-trunk.yaml +105 -0
- package/templates/omgkit/workflow.yaml +145 -0
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Git Hooks Integration
|
|
3
|
+
description: The agent implements Git hooks that integrate with the workflow config system, automating pre-commit checks, commit message validation, pre-push tests, and post-merge actions.
|
|
4
|
+
category: devops
|
|
5
|
+
related_skills:
|
|
6
|
+
- devops/workflow-config
|
|
7
|
+
- devops/github-actions
|
|
8
|
+
- testing/comprehensive-testing
|
|
9
|
+
- methodology/test-driven-development
|
|
10
|
+
related_commands:
|
|
11
|
+
- /hooks:setup
|
|
12
|
+
- /hooks:run
|
|
13
|
+
- /workflow:init
|
|
14
|
+
- /dev:test
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Git Hooks Integration
|
|
18
|
+
|
|
19
|
+
## Overview
|
|
20
|
+
|
|
21
|
+
Git Hooks Integration provides automated enforcement of workflow rules through Git hooks. Hooks are configured in `.omgkit/workflow.yaml` and automatically installed to `.git/hooks/`. This ensures consistent code quality, commit conventions, and testing before code reaches the remote repository.
|
|
22
|
+
|
|
23
|
+
## Available Hooks
|
|
24
|
+
|
|
25
|
+
| Hook | Trigger | Purpose |
|
|
26
|
+
|------|---------|---------|
|
|
27
|
+
| `pre-commit` | Before commit | Lint, format, type-check |
|
|
28
|
+
| `commit-msg` | After commit message | Validate conventional commits |
|
|
29
|
+
| `pre-push` | Before push | Run tests, security scan |
|
|
30
|
+
| `post-merge` | After merge/pull | Install deps, run migrations |
|
|
31
|
+
| `post-checkout` | After checkout | Environment setup |
|
|
32
|
+
|
|
33
|
+
## Configuration
|
|
34
|
+
|
|
35
|
+
### Basic Configuration
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
# .omgkit/workflow.yaml
|
|
39
|
+
hooks:
|
|
40
|
+
pre_commit:
|
|
41
|
+
enabled: true
|
|
42
|
+
actions:
|
|
43
|
+
- lint
|
|
44
|
+
- format
|
|
45
|
+
|
|
46
|
+
commit_msg:
|
|
47
|
+
enabled: true
|
|
48
|
+
validate_conventional: true
|
|
49
|
+
|
|
50
|
+
pre_push:
|
|
51
|
+
enabled: true
|
|
52
|
+
actions:
|
|
53
|
+
- test
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Full Configuration
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
hooks:
|
|
60
|
+
# Pre-commit: runs before each commit
|
|
61
|
+
pre_commit:
|
|
62
|
+
enabled: true
|
|
63
|
+
actions:
|
|
64
|
+
- lint # Run ESLint/Pylint/etc
|
|
65
|
+
- type-check # TypeScript/mypy/Flow
|
|
66
|
+
- format # Prettier/Black/gofmt
|
|
67
|
+
- secrets-check # Detect leaked secrets
|
|
68
|
+
fail_fast: true # Stop on first failure
|
|
69
|
+
staged_only: true # Only check staged files
|
|
70
|
+
bypass_key: "SKIP_HOOKS" # Env var to bypass
|
|
71
|
+
|
|
72
|
+
# Commit message validation
|
|
73
|
+
commit_msg:
|
|
74
|
+
enabled: true
|
|
75
|
+
validate_conventional: true
|
|
76
|
+
allowed_types:
|
|
77
|
+
- feat
|
|
78
|
+
- fix
|
|
79
|
+
- docs
|
|
80
|
+
- style
|
|
81
|
+
- refactor
|
|
82
|
+
- perf
|
|
83
|
+
- test
|
|
84
|
+
- chore
|
|
85
|
+
- ci
|
|
86
|
+
- build
|
|
87
|
+
require_scope: false
|
|
88
|
+
max_subject_length: 72
|
|
89
|
+
require_body: false
|
|
90
|
+
require_issue: false
|
|
91
|
+
issue_pattern: "#[0-9]+"
|
|
92
|
+
|
|
93
|
+
# Pre-push: runs before pushing
|
|
94
|
+
pre_push:
|
|
95
|
+
enabled: true
|
|
96
|
+
actions:
|
|
97
|
+
- test # Run test suite
|
|
98
|
+
- security-scan # npm audit / safety check
|
|
99
|
+
- build # Verify build works
|
|
100
|
+
skip_on_ci: true # Skip in CI environment
|
|
101
|
+
protected_branches:
|
|
102
|
+
- main
|
|
103
|
+
- develop
|
|
104
|
+
require_review_for:
|
|
105
|
+
- main
|
|
106
|
+
|
|
107
|
+
# Post-merge: runs after git pull/merge
|
|
108
|
+
post_merge:
|
|
109
|
+
enabled: false
|
|
110
|
+
actions:
|
|
111
|
+
- install # npm install / pip install
|
|
112
|
+
- migrate # Database migrations
|
|
113
|
+
- generate # Code generation
|
|
114
|
+
notify: false
|
|
115
|
+
|
|
116
|
+
# Post-checkout: runs after git checkout
|
|
117
|
+
post_checkout:
|
|
118
|
+
enabled: false
|
|
119
|
+
actions:
|
|
120
|
+
- install # Install dependencies
|
|
121
|
+
- env-check # Verify environment
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Hook Actions
|
|
125
|
+
|
|
126
|
+
### Pre-commit Actions
|
|
127
|
+
|
|
128
|
+
| Action | Description | Command |
|
|
129
|
+
|--------|-------------|---------|
|
|
130
|
+
| `lint` | Run linter | Auto-detected |
|
|
131
|
+
| `format` | Format code | Auto-detected |
|
|
132
|
+
| `type-check` | Type checking | Auto-detected |
|
|
133
|
+
| `secrets-check` | Detect secrets | git-secrets |
|
|
134
|
+
| `test-staged` | Test staged files | vitest related |
|
|
135
|
+
|
|
136
|
+
**Auto-detection Logic:**
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
# JavaScript/TypeScript
|
|
140
|
+
lint: npx eslint --fix
|
|
141
|
+
format: npx prettier --write
|
|
142
|
+
type-check: npx tsc --noEmit
|
|
143
|
+
|
|
144
|
+
# Python
|
|
145
|
+
lint: ruff check --fix
|
|
146
|
+
format: black
|
|
147
|
+
type-check: mypy
|
|
148
|
+
|
|
149
|
+
# Go
|
|
150
|
+
lint: golangci-lint run
|
|
151
|
+
format: gofmt -w
|
|
152
|
+
type-check: go vet
|
|
153
|
+
|
|
154
|
+
# Rust
|
|
155
|
+
lint: cargo clippy
|
|
156
|
+
format: cargo fmt
|
|
157
|
+
type-check: cargo check
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Pre-push Actions
|
|
161
|
+
|
|
162
|
+
| Action | Description | Command |
|
|
163
|
+
|--------|-------------|---------|
|
|
164
|
+
| `test` | Run tests | Auto-detected |
|
|
165
|
+
| `test-coverage` | With coverage | Auto-detected |
|
|
166
|
+
| `security-scan` | Security audit | Auto-detected |
|
|
167
|
+
| `build` | Verify build | Auto-detected |
|
|
168
|
+
| `review` | Claude review | /dev:review |
|
|
169
|
+
|
|
170
|
+
**Auto-detection Logic:**
|
|
171
|
+
|
|
172
|
+
```yaml
|
|
173
|
+
# JavaScript/TypeScript
|
|
174
|
+
test: npm test
|
|
175
|
+
security-scan: npm audit
|
|
176
|
+
build: npm run build
|
|
177
|
+
|
|
178
|
+
# Python
|
|
179
|
+
test: pytest
|
|
180
|
+
security-scan: safety check
|
|
181
|
+
build: python -m build
|
|
182
|
+
|
|
183
|
+
# Go
|
|
184
|
+
test: go test ./...
|
|
185
|
+
security-scan: gosec ./...
|
|
186
|
+
build: go build
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Installation
|
|
190
|
+
|
|
191
|
+
### Automatic Setup
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Setup hooks from workflow.yaml
|
|
195
|
+
/hooks:setup
|
|
196
|
+
|
|
197
|
+
# Output:
|
|
198
|
+
# Installing Git Hooks
|
|
199
|
+
# --------------------
|
|
200
|
+
# Reading config from .omgkit/workflow.yaml
|
|
201
|
+
# Creating pre-commit hook...
|
|
202
|
+
# Creating commit-msg hook...
|
|
203
|
+
# Creating pre-push hook...
|
|
204
|
+
# Done! 3 hooks installed.
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Manual Setup
|
|
208
|
+
|
|
209
|
+
Run `/hooks:setup` which creates executable scripts in `.git/hooks/`:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
.git/hooks/
|
|
213
|
+
├── pre-commit # Lint, format, type-check
|
|
214
|
+
├── commit-msg # Validate commit message
|
|
215
|
+
├── pre-push # Test, security scan
|
|
216
|
+
└── post-merge # Install, migrate
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Hook Script Templates
|
|
220
|
+
|
|
221
|
+
### Pre-commit Hook
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
#!/bin/bash
|
|
225
|
+
# Generated by OMGKIT - Do not edit manually
|
|
226
|
+
# Regenerate with: /hooks:setup
|
|
227
|
+
|
|
228
|
+
set -e
|
|
229
|
+
|
|
230
|
+
# Check for bypass
|
|
231
|
+
if [ -n "$SKIP_HOOKS" ]; then
|
|
232
|
+
echo "Skipping pre-commit hooks (SKIP_HOOKS is set)"
|
|
233
|
+
exit 0
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
echo "Running pre-commit checks..."
|
|
237
|
+
|
|
238
|
+
# Get staged files
|
|
239
|
+
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
|
|
240
|
+
|
|
241
|
+
if [ -z "$STAGED_FILES" ]; then
|
|
242
|
+
echo "No staged files to check"
|
|
243
|
+
exit 0
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
# Action: lint
|
|
247
|
+
echo " Running lint..."
|
|
248
|
+
if command -v npx &> /dev/null && [ -f "package.json" ]; then
|
|
249
|
+
npx eslint --fix $STAGED_FILES
|
|
250
|
+
elif command -v ruff &> /dev/null; then
|
|
251
|
+
ruff check --fix $STAGED_FILES
|
|
252
|
+
fi
|
|
253
|
+
|
|
254
|
+
# Action: format
|
|
255
|
+
echo " Running format..."
|
|
256
|
+
if command -v npx &> /dev/null && [ -f "package.json" ]; then
|
|
257
|
+
npx prettier --write $STAGED_FILES
|
|
258
|
+
git add $STAGED_FILES
|
|
259
|
+
fi
|
|
260
|
+
|
|
261
|
+
# Action: type-check
|
|
262
|
+
echo " Running type-check..."
|
|
263
|
+
if [ -f "tsconfig.json" ]; then
|
|
264
|
+
npx tsc --noEmit
|
|
265
|
+
fi
|
|
266
|
+
|
|
267
|
+
echo "Pre-commit checks passed!"
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Commit-msg Hook
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
#!/bin/bash
|
|
274
|
+
# Generated by OMGKIT - Do not edit manually
|
|
275
|
+
|
|
276
|
+
set -e
|
|
277
|
+
|
|
278
|
+
COMMIT_MSG_FILE=$1
|
|
279
|
+
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
|
|
280
|
+
|
|
281
|
+
# Conventional commit pattern
|
|
282
|
+
PATTERN="^(feat|fix|docs|style|refactor|perf|test|chore|ci|build)(\(.+\))?: .{1,72}$"
|
|
283
|
+
|
|
284
|
+
# Check first line
|
|
285
|
+
FIRST_LINE=$(echo "$COMMIT_MSG" | head -n1)
|
|
286
|
+
|
|
287
|
+
if ! echo "$FIRST_LINE" | grep -qE "$PATTERN"; then
|
|
288
|
+
echo "ERROR: Invalid commit message format"
|
|
289
|
+
echo ""
|
|
290
|
+
echo "Expected format: type(scope): subject"
|
|
291
|
+
echo " type: feat|fix|docs|style|refactor|perf|test|chore|ci|build"
|
|
292
|
+
echo " scope: optional, in parentheses"
|
|
293
|
+
echo " subject: max 72 characters"
|
|
294
|
+
echo ""
|
|
295
|
+
echo "Examples:"
|
|
296
|
+
echo " feat: add user authentication"
|
|
297
|
+
echo " fix(api): resolve null pointer exception"
|
|
298
|
+
echo " docs(readme): update installation guide"
|
|
299
|
+
echo ""
|
|
300
|
+
echo "Your message: $FIRST_LINE"
|
|
301
|
+
exit 1
|
|
302
|
+
fi
|
|
303
|
+
|
|
304
|
+
# Check subject length
|
|
305
|
+
SUBJECT_LENGTH=${#FIRST_LINE}
|
|
306
|
+
MAX_LENGTH=72
|
|
307
|
+
|
|
308
|
+
if [ $SUBJECT_LENGTH -gt $MAX_LENGTH ]; then
|
|
309
|
+
echo "ERROR: Commit subject too long ($SUBJECT_LENGTH > $MAX_LENGTH)"
|
|
310
|
+
exit 1
|
|
311
|
+
fi
|
|
312
|
+
|
|
313
|
+
echo "Commit message validated!"
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Pre-push Hook
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
#!/bin/bash
|
|
320
|
+
# Generated by OMGKIT - Do not edit manually
|
|
321
|
+
|
|
322
|
+
set -e
|
|
323
|
+
|
|
324
|
+
# Skip in CI
|
|
325
|
+
if [ -n "$CI" ] || [ -n "$GITHUB_ACTIONS" ]; then
|
|
326
|
+
echo "Skipping pre-push hooks (CI environment)"
|
|
327
|
+
exit 0
|
|
328
|
+
fi
|
|
329
|
+
|
|
330
|
+
# Check for bypass
|
|
331
|
+
if [ -n "$SKIP_HOOKS" ]; then
|
|
332
|
+
echo "Skipping pre-push hooks (SKIP_HOOKS is set)"
|
|
333
|
+
exit 0
|
|
334
|
+
fi
|
|
335
|
+
|
|
336
|
+
echo "Running pre-push checks..."
|
|
337
|
+
|
|
338
|
+
# Action: test
|
|
339
|
+
echo " Running tests..."
|
|
340
|
+
if [ -f "package.json" ]; then
|
|
341
|
+
npm test
|
|
342
|
+
elif [ -f "pytest.ini" ] || [ -f "pyproject.toml" ]; then
|
|
343
|
+
pytest
|
|
344
|
+
elif [ -f "go.mod" ]; then
|
|
345
|
+
go test ./...
|
|
346
|
+
fi
|
|
347
|
+
|
|
348
|
+
# Action: security-scan
|
|
349
|
+
echo " Running security scan..."
|
|
350
|
+
if [ -f "package.json" ]; then
|
|
351
|
+
npm audit --audit-level=high || true
|
|
352
|
+
elif command -v safety &> /dev/null; then
|
|
353
|
+
safety check || true
|
|
354
|
+
fi
|
|
355
|
+
|
|
356
|
+
echo "Pre-push checks passed!"
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Commands
|
|
360
|
+
|
|
361
|
+
### /hooks:setup
|
|
362
|
+
|
|
363
|
+
Install or update Git hooks based on workflow config:
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
/hooks:setup
|
|
367
|
+
|
|
368
|
+
# Options:
|
|
369
|
+
/hooks:setup --force # Overwrite existing hooks
|
|
370
|
+
/hooks:setup --dry-run # Show what would be created
|
|
371
|
+
/hooks:setup --hook=pre-commit # Setup specific hook only
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### /hooks:run
|
|
375
|
+
|
|
376
|
+
Manually run hook actions:
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
/hooks:run pre-commit # Run pre-commit actions
|
|
380
|
+
/hooks:run commit-msg # Validate last commit message
|
|
381
|
+
/hooks:run pre-push # Run pre-push actions
|
|
382
|
+
|
|
383
|
+
# Run specific action
|
|
384
|
+
/hooks:run pre-commit --action=lint
|
|
385
|
+
/hooks:run pre-commit --action=format
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## Bypassing Hooks
|
|
389
|
+
|
|
390
|
+
### Temporary Bypass
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
# Skip all hooks for one command
|
|
394
|
+
SKIP_HOOKS=1 git commit -m "wip: temp commit"
|
|
395
|
+
|
|
396
|
+
# Git native skip (not recommended)
|
|
397
|
+
git commit --no-verify -m "emergency fix"
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Permanent Exclusions
|
|
401
|
+
|
|
402
|
+
```yaml
|
|
403
|
+
hooks:
|
|
404
|
+
pre_commit:
|
|
405
|
+
exclude_paths:
|
|
406
|
+
- "vendor/**"
|
|
407
|
+
- "node_modules/**"
|
|
408
|
+
- "*.generated.*"
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## Troubleshooting
|
|
412
|
+
|
|
413
|
+
### Hook Not Executing
|
|
414
|
+
|
|
415
|
+
1. Check hook is executable:
|
|
416
|
+
```bash
|
|
417
|
+
ls -la .git/hooks/pre-commit
|
|
418
|
+
chmod +x .git/hooks/pre-commit
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
2. Regenerate hooks:
|
|
422
|
+
```bash
|
|
423
|
+
/hooks:setup --force
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
3. Check config:
|
|
427
|
+
```yaml
|
|
428
|
+
hooks:
|
|
429
|
+
pre_commit:
|
|
430
|
+
enabled: true # Must be true
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Hook Failing
|
|
434
|
+
|
|
435
|
+
1. Run manually to see errors:
|
|
436
|
+
```bash
|
|
437
|
+
/hooks:run pre-commit
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
2. Check staged files:
|
|
441
|
+
```bash
|
|
442
|
+
git diff --cached --name-only
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
3. Bypass temporarily:
|
|
446
|
+
```bash
|
|
447
|
+
SKIP_HOOKS=1 git commit -m "message"
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Performance Issues
|
|
451
|
+
|
|
452
|
+
1. Use staged-only checking:
|
|
453
|
+
```yaml
|
|
454
|
+
hooks:
|
|
455
|
+
pre_commit:
|
|
456
|
+
staged_only: true
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
2. Skip slow checks locally:
|
|
460
|
+
```yaml
|
|
461
|
+
hooks:
|
|
462
|
+
pre_push:
|
|
463
|
+
skip_on_ci: true # Run full checks in CI only
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
## Integration with CI/CD
|
|
467
|
+
|
|
468
|
+
Hooks complement CI/CD but don't replace it:
|
|
469
|
+
|
|
470
|
+
| Check | Local Hook | CI/CD |
|
|
471
|
+
|-------|-----------|-------|
|
|
472
|
+
| Lint | pre-commit | Yes |
|
|
473
|
+
| Format | pre-commit | Yes |
|
|
474
|
+
| Type-check | pre-commit | Yes |
|
|
475
|
+
| Unit tests | pre-push | Yes |
|
|
476
|
+
| Integration tests | No | Yes |
|
|
477
|
+
| E2E tests | No | Yes |
|
|
478
|
+
| Security scan | pre-push | Yes |
|
|
479
|
+
| Build | pre-push | Yes |
|
|
480
|
+
| Deploy | No | Yes |
|
|
481
|
+
|
|
482
|
+
## Best Practices
|
|
483
|
+
|
|
484
|
+
### Fast Pre-commit
|
|
485
|
+
|
|
486
|
+
Keep pre-commit under 5 seconds:
|
|
487
|
+
|
|
488
|
+
```yaml
|
|
489
|
+
hooks:
|
|
490
|
+
pre_commit:
|
|
491
|
+
actions:
|
|
492
|
+
- lint # Fast
|
|
493
|
+
- format # Fast
|
|
494
|
+
staged_only: true
|
|
495
|
+
# Move slow checks to pre-push
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Comprehensive Pre-push
|
|
499
|
+
|
|
500
|
+
Run thorough checks before pushing:
|
|
501
|
+
|
|
502
|
+
```yaml
|
|
503
|
+
hooks:
|
|
504
|
+
pre_push:
|
|
505
|
+
actions:
|
|
506
|
+
- test
|
|
507
|
+
- type-check
|
|
508
|
+
- security-scan
|
|
509
|
+
- build
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### Team Consistency
|
|
513
|
+
|
|
514
|
+
Commit `.omgkit/workflow.yaml` to ensure all team members have same hooks:
|
|
515
|
+
|
|
516
|
+
```bash
|
|
517
|
+
git add .omgkit/workflow.yaml
|
|
518
|
+
git commit -m "chore: add workflow config"
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
## Related Skills
|
|
522
|
+
|
|
523
|
+
- `devops/workflow-config` - Central configuration system
|
|
524
|
+
- `devops/github-actions` - CI/CD workflows
|
|
525
|
+
- `testing/comprehensive-testing` - Test strategies
|
|
526
|
+
- `methodology/test-driven-development` - TDD practices
|