claude-git-hooks 1.5.2 → 1.5.4
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/CHANGELOG.md +34 -0
- package/LICENSE +0 -0
- package/README.md +22 -30
- package/bin/claude-hooks +23 -28
- package/package.json +1 -2
- package/templates/CLAUDE_ANALYSIS_PROMPT_SONAR.md +0 -0
- package/templates/CLAUDE_PRE_COMMIT_SONAR.md +0 -0
- package/templates/CLAUDE_RESOLUTION_PROMPT.md +0 -1
- package/templates/check-version.sh +0 -0
- package/templates/pre-commit +78 -108
- package/templates/prepare-commit-msg +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,40 @@ Todos los cambios notables en este proyecto se documentarán en este archivo.
|
|
|
5
5
|
El formato está basado en [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.5.4] - 2024-12-22
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- 🔧 **Generación de prompt de resolución en modo SonarQube**
|
|
13
|
+
- Ahora se genera correctamente `claude_resolution_prompt.md` cuando el Quality Gate falla
|
|
14
|
+
- El archivo se genera cuando hay `blockingIssues`, independiente del tipo de fallo
|
|
15
|
+
- Corregido el flujo para que siempre muestre los issues críticos antes de generar el prompt
|
|
16
|
+
|
|
17
|
+
- 🎯 **Unificación de lógica de análisis**
|
|
18
|
+
- Eliminada lógica duplicada entre modo "clásico" y SonarQube
|
|
19
|
+
- Ahora siempre se usa modo SonarQube (como se especificó en v1.4.1)
|
|
20
|
+
- Simplificación del flujo de decisión en el pre-commit hook
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- 📝 Refactorización del hook pre-commit para mayor claridad y mantenibilidad
|
|
25
|
+
- 🔄 La función `generate_resolution_prompt` ahora se llama consistentemente cuando hay issues bloqueantes
|
|
26
|
+
|
|
27
|
+
## [1.5.3] - 2025-09-12
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- 🔧 Comando `analyze-diff` ahora siempre compara con ramas origin
|
|
32
|
+
- Si se especifica rama: compara con `origin/rama-especificada`
|
|
33
|
+
- Si no se especifica: compara con `origin/rama-actual`
|
|
34
|
+
- Fallback automático a `origin/develop` y luego `origin/main` si no existe la rama origin
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- 📝 Documentación mejorada con intro atractiva y características principales
|
|
39
|
+
- ⚠️ Aclaración importante sobre uso exclusivo en WSL/Ubuntu (no PowerShell/CMD)
|
|
40
|
+
- 🔗 Enlaces directos a configuración previa en sección de instalación
|
|
41
|
+
|
|
8
42
|
## [1.5.2] - 2025-09-11
|
|
9
43
|
|
|
10
44
|
### Changed
|
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# Pre-commit Hook con Claude CLI
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
Otras funciones de interés:
|
|
3
|
+
🚀 **Transforma tu flujo de desarrollo con IA**: análisis de código instantáneo, mensajes de commit automáticos y generación de PRs perfectas. Claude revisa tu código antes de cada commit, detecta issues críticos al estilo SonarQube, y genera toda la documentación que necesitas. ¿Lo mejor? Se ejecuta localmente sin contaminar tu CI/CD.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
## 🎯 Características principales
|
|
6
|
+
|
|
7
|
+
- 🔍 **Análisis de código pre-commit**: Detecta issues críticos antes de que lleguen al repo
|
|
8
|
+
- 💬 **Mensajes de commit automáticos**: Escribe "auto" y Claude genera el mensaje perfecto
|
|
9
|
+
- 📋 **Generación de PRs**: Título, descripción y tests sugeridos con un solo comando
|
|
10
|
+
- 🎨 **Modo SonarQube**: Métricas de calidad y Quality Gate integrados
|
|
11
|
+
- 🚫 **Skip inteligente**: Excluye código legacy con comentarios SKIP-ANALYSIS
|
|
12
|
+
- 🔄 **Auto-actualización**: Se mantiene actualizado automáticamente
|
|
8
13
|
|
|
9
14
|
## 📋 CHEATSHEET
|
|
10
15
|
|
|
@@ -14,10 +19,10 @@ Otras funciones de interés:
|
|
|
14
19
|
# Commit rápido sin análisis + mensaje automático
|
|
15
20
|
git commit --no-verify -m "auto"
|
|
16
21
|
|
|
17
|
-
# Analizar diferencias con rama
|
|
22
|
+
# Analizar diferencias con origin de la rama actual
|
|
18
23
|
claude-hooks analyze-diff
|
|
19
24
|
|
|
20
|
-
# Analizar diferencias para PR (comparar con develop
|
|
25
|
+
# Analizar diferencias para PR (comparar con origin/develop)
|
|
21
26
|
claude-hooks analyze-diff develop
|
|
22
27
|
|
|
23
28
|
# Reinstalar durante desarrollo (después de npm link)
|
|
@@ -26,8 +31,16 @@ claude-hooks install --force --skip-auth
|
|
|
26
31
|
|
|
27
32
|
### 📦 Instalación y Gestión
|
|
28
33
|
|
|
34
|
+
⚠️ **IMPORTANTE**: Todo debe ejecutarse desde consola WSL/Ubuntu (no PowerShell ni CMD). Ver [Configuración Previa](#-configuración-previa-importante) antes de comenzar.
|
|
35
|
+
|
|
36
|
+
Se debe instalar el paquete globalmente, para luego gestionarlo localmente en cada repositorio.
|
|
37
|
+
|
|
29
38
|
```bash
|
|
30
|
-
#
|
|
39
|
+
# En consola WSL/Ubuntu - Instalar globalmente
|
|
40
|
+
npm install -g claude-git-hooks
|
|
41
|
+
|
|
42
|
+
# Luego en cada proyecto (también desde WSL/Ubuntu)
|
|
43
|
+
cd /tu/proyecto
|
|
31
44
|
claude-hooks install
|
|
32
45
|
|
|
33
46
|
# Actualizar a última versión
|
|
@@ -123,28 +136,7 @@ git commit -m "fix: resolver issues"
|
|
|
123
136
|
|
|
124
137
|
## 🔧 Configuración Previa Importante
|
|
125
138
|
|
|
126
|
-
###
|
|
127
|
-
|
|
128
|
-
Debido a que Claude CLI corre en WSL y el desarrollo puede hacerse en Windows, es crucial configurar correctamente los line endings para evitar que los archivos de hooks se corrompan:
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
# IMPORTANTE: Usar la misma configuración en WSL y Windows
|
|
132
|
-
# Recomendación: usar 'input' en ambos entornos
|
|
133
|
-
|
|
134
|
-
# En WSL
|
|
135
|
-
git config core.autocrlf input
|
|
136
|
-
|
|
137
|
-
# En PowerShell/Windows
|
|
138
|
-
git config core.autocrlf input
|
|
139
|
-
|
|
140
|
-
# Verificar configuración actual
|
|
141
|
-
git config --local core.autocrlf
|
|
142
|
-
git config --global core.autocrlf
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
**⚠️ ADVERTENCIA**: Si tienes `core.autocrlf = true` en local e `input` en global, esto puede causar que los archivos de los hooks se vacíen. Asegúrate de que ambas configuraciones sean consistentes.
|
|
146
|
-
|
|
147
|
-
### 2. Credenciales Git en WSL
|
|
139
|
+
### Credenciales Git en WSL
|
|
148
140
|
|
|
149
141
|
Debes configurar tus credenciales de git nuevamente en WSL:
|
|
150
142
|
|
|
@@ -264,7 +256,7 @@ Si no existe un `.gitignore`, se creará uno nuevo. Si ya existe, las entradas s
|
|
|
264
256
|
|
|
265
257
|
### Características adicionales
|
|
266
258
|
|
|
267
|
-
- **Generación de información para Pull Requests**: `claude-hooks analyze-
|
|
259
|
+
- **Generación de información para Pull Requests**: `claude-hooks analyze-diff [branch]` para comparar rama local con rama origin, propone nombre para rama actual, título y detalles para pull request, da tips para verificar trabajo. Si se especifica branch, compara con origin/branch. Si no, compara con origin de la rama actual. Este comando genera automáticamente:
|
|
268
260
|
- 📝 Título de PR conciso (máx. 72 caracteres)
|
|
269
261
|
- 📄 Descripción detallada con markdown
|
|
270
262
|
- 🌿 Nombre de rama sugerido (formato: tipo/descripcion)
|
package/bin/claude-hooks
CHANGED
|
@@ -808,15 +808,19 @@ function analyzeDiff(args) {
|
|
|
808
808
|
return;
|
|
809
809
|
}
|
|
810
810
|
|
|
811
|
+
// Update remote references
|
|
812
|
+
execSync('git fetch', { stdio: 'ignore' });
|
|
813
|
+
|
|
811
814
|
let baseBranch, compareWith, contextDescription;
|
|
812
815
|
|
|
813
816
|
if (args[0]) {
|
|
814
|
-
// Case with argument: compare current branch vs specified
|
|
815
|
-
|
|
817
|
+
// Case with argument: compare current branch vs origin/specified-branch
|
|
818
|
+
const targetBranch = args[0];
|
|
819
|
+
baseBranch = `origin/${targetBranch}`;
|
|
816
820
|
compareWith = `${baseBranch}...HEAD`;
|
|
817
821
|
contextDescription = `${currentBranch} vs ${baseBranch}`;
|
|
818
822
|
|
|
819
|
-
// Check that the
|
|
823
|
+
// Check that the origin branch exists
|
|
820
824
|
try {
|
|
821
825
|
execSync(`git rev-parse --verify ${baseBranch}`, { stdio: 'ignore' });
|
|
822
826
|
} catch (e) {
|
|
@@ -824,38 +828,34 @@ function analyzeDiff(args) {
|
|
|
824
828
|
return;
|
|
825
829
|
}
|
|
826
830
|
} else {
|
|
827
|
-
// Case without argument: compare
|
|
831
|
+
// Case without argument: compare current branch vs origin/current-branch
|
|
832
|
+
baseBranch = `origin/${currentBranch}`;
|
|
833
|
+
compareWith = `${baseBranch}...HEAD`;
|
|
834
|
+
contextDescription = `${currentBranch} vs ${baseBranch}`;
|
|
835
|
+
|
|
836
|
+
// Check that the origin branch exists
|
|
828
837
|
try {
|
|
829
|
-
|
|
830
|
-
const remoteBranch = execSync(`git rev-parse --abbrev-ref ${currentBranch}@{upstream}`, { encoding: 'utf8' }).trim();
|
|
831
|
-
|
|
832
|
-
// Update remote references
|
|
833
|
-
execSync('git fetch', { stdio: 'ignore' });
|
|
834
|
-
|
|
835
|
-
baseBranch = remoteBranch;
|
|
836
|
-
compareWith = `HEAD..${remoteBranch}`;
|
|
837
|
-
contextDescription = `local changes without push in ${currentBranch}`;
|
|
838
|
-
|
|
839
|
-
info(`Comparing local changes vs remote: ${remoteBranch}`);
|
|
838
|
+
execSync(`git rev-parse --verify ${baseBranch}`, { stdio: 'ignore' });
|
|
840
839
|
} catch (e) {
|
|
841
|
-
//
|
|
842
|
-
baseBranch = 'develop';
|
|
840
|
+
// Try fallback to origin/develop
|
|
841
|
+
baseBranch = 'origin/develop';
|
|
843
842
|
compareWith = `${baseBranch}...HEAD`;
|
|
844
|
-
contextDescription = `${currentBranch} vs ${baseBranch} (
|
|
843
|
+
contextDescription = `${currentBranch} vs ${baseBranch} (fallback)`;
|
|
845
844
|
|
|
846
845
|
try {
|
|
847
846
|
execSync(`git rev-parse --verify ${baseBranch}`, { stdio: 'ignore' });
|
|
848
|
-
warning(`
|
|
847
|
+
warning(`Branch origin/${currentBranch} does not exist. Using ${baseBranch} as fallback.`);
|
|
849
848
|
} catch (e2) {
|
|
850
|
-
|
|
849
|
+
// Try fallback to origin/main
|
|
850
|
+
baseBranch = 'origin/main';
|
|
851
851
|
compareWith = `${baseBranch}...HEAD`;
|
|
852
852
|
contextDescription = `${currentBranch} vs ${baseBranch} (fallback)`;
|
|
853
853
|
|
|
854
854
|
try {
|
|
855
855
|
execSync(`git rev-parse --verify ${baseBranch}`, { stdio: 'ignore' });
|
|
856
|
-
warning(`No develop
|
|
856
|
+
warning(`No origin/develop branch. Using ${baseBranch} as fallback.`);
|
|
857
857
|
} catch (e3) {
|
|
858
|
-
error('Could not find a valid comparison branch.');
|
|
858
|
+
error('Could not find a valid comparison branch (tried origin/current, origin/develop, origin/main).');
|
|
859
859
|
return;
|
|
860
860
|
}
|
|
861
861
|
}
|
|
@@ -867,12 +867,7 @@ function analyzeDiff(args) {
|
|
|
867
867
|
// Get modified files
|
|
868
868
|
let diffFiles;
|
|
869
869
|
try {
|
|
870
|
-
|
|
871
|
-
if (!args[0] && compareWith.includes('HEAD..')) {
|
|
872
|
-
diffFiles = execSync(`git diff ${compareWith} --name-only`, { encoding: 'utf8' }).trim();
|
|
873
|
-
} else {
|
|
874
|
-
diffFiles = execSync(`git diff ${compareWith} --name-only`, { encoding: 'utf8' }).trim();
|
|
875
|
-
}
|
|
870
|
+
diffFiles = execSync(`git diff ${compareWith} --name-only`, { encoding: 'utf8' }).trim();
|
|
876
871
|
|
|
877
872
|
if (!diffFiles) {
|
|
878
873
|
// Check if there are staged or unstaged changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-git-hooks",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"description": "Git hooks con Claude CLI para análisis de código y generación automática de mensajes de commit",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
"engines": {
|
|
29
29
|
"node": ">=14.0.0"
|
|
30
30
|
},
|
|
31
|
-
"dependencies": {},
|
|
32
31
|
"preferGlobal": true,
|
|
33
32
|
"files": [
|
|
34
33
|
"bin/",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/templates/pre-commit
CHANGED
|
@@ -332,125 +332,95 @@ if $CLAUDE_CLI < "$PROMPT_FILE" > "$RESPONSE_FILE" 2>&1; then
|
|
|
332
332
|
BLOCKING_ISSUES=$(echo "$JSON_RESPONSE" | jq -r '.blockingIssues[].description' 2>/dev/null | sed '/^$/d')
|
|
333
333
|
fi
|
|
334
334
|
|
|
335
|
+
# Always use SonarQube mode (as per v1.4.1)
|
|
335
336
|
QUALITY_GATE=$(echo "$JSON_RESPONSE" | jq -r '.QUALITY_GATE // ""' 2>/dev/null)
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
337
|
+
|
|
338
|
+
# Show SonarQube style results
|
|
339
|
+
echo
|
|
340
|
+
echo "╔════════════════════════════════════════════════════════════════════╗"
|
|
341
|
+
echo "║ CODE QUALITY ANALYSIS ║"
|
|
342
|
+
echo "╚════════════════════════════════════════════════════════════════════╝"
|
|
343
|
+
echo
|
|
344
|
+
|
|
345
|
+
# Quality Gate Status
|
|
346
|
+
if [ "$QUALITY_GATE" = "PASSED" ]; then
|
|
347
|
+
echo -e "${GREEN}✓ Quality Gate: PASSED${NC}"
|
|
348
|
+
else
|
|
349
|
+
echo -e "${RED}✗ Quality Gate: FAILED${NC}"
|
|
350
|
+
fi
|
|
351
|
+
echo
|
|
352
|
+
|
|
353
|
+
# Metrics
|
|
354
|
+
METRICS=$(echo "$JSON_RESPONSE" | jq -r '.metrics // {}' 2>/dev/null)
|
|
355
|
+
if [ "$METRICS" != "{}" ] && [ "$METRICS" != "null" ]; then
|
|
356
|
+
echo "📊 METRICS"
|
|
357
|
+
echo "├─ Reliability: $(echo "$METRICS" | jq -r '.reliability // "?"' 2>/dev/null)"
|
|
358
|
+
echo "├─ Security: $(echo "$METRICS" | jq -r '.security // "?"' 2>/dev/null)"
|
|
359
|
+
echo "├─ Maintainability: $(echo "$METRICS" | jq -r '.maintainability // "?"' 2>/dev/null)"
|
|
360
|
+
echo "├─ Coverage: $(echo "$METRICS" | jq -r '.coverage // "?"' 2>/dev/null)%"
|
|
361
|
+
echo "├─ Duplications: $(echo "$METRICS" | jq -r '.duplications // "?"' 2>/dev/null)%"
|
|
362
|
+
echo "└─ Complexity: $(echo "$METRICS" | jq -r '.complexity // "?"' 2>/dev/null)"
|
|
343
363
|
echo
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
364
|
+
fi
|
|
365
|
+
|
|
366
|
+
# Issues Summary
|
|
367
|
+
ISSUES=$(echo "$JSON_RESPONSE" | jq -r '.issues // {}' 2>/dev/null)
|
|
368
|
+
if [ "$ISSUES" != "{}" ] && [ "$ISSUES" != "null" ]; then
|
|
369
|
+
echo "📋 ISSUES SUMMARY"
|
|
370
|
+
BLOCKER=$(echo "$ISSUES" | jq -r '.blocker // 0' 2>/dev/null)
|
|
371
|
+
CRITICAL=$(echo "$ISSUES" | jq -r '.critical // 0' 2>/dev/null)
|
|
372
|
+
MAJOR=$(echo "$ISSUES" | jq -r '.major // 0' 2>/dev/null)
|
|
373
|
+
MINOR=$(echo "$ISSUES" | jq -r '.minor // 0' 2>/dev/null)
|
|
374
|
+
INFO=$(echo "$ISSUES" | jq -r '.info // 0' 2>/dev/null)
|
|
375
|
+
TOTAL=$((BLOCKER + CRITICAL + MAJOR + MINOR + INFO))
|
|
376
|
+
|
|
377
|
+
echo "Total: $TOTAL issues found"
|
|
378
|
+
[ "$BLOCKER" -gt 0 ] && echo -e " ${RED}🔴 Blocker: $BLOCKER${NC}"
|
|
379
|
+
[ "$CRITICAL" -gt 0 ] && echo -e " ${RED}🟠 Critical: $CRITICAL${NC}"
|
|
380
|
+
[ "$MAJOR" -gt 0 ] && echo -e " ${YELLOW}🟡 Major: $MAJOR${NC}"
|
|
381
|
+
[ "$MINOR" -gt 0 ] && echo " 🔵 Minor: $MINOR"
|
|
382
|
+
[ "$INFO" -gt 0 ] && echo " ⚪ Info: $INFO"
|
|
351
383
|
echo
|
|
352
|
-
|
|
353
|
-
# Metrics
|
|
354
|
-
METRICS=$(echo "$JSON_RESPONSE" | jq -r '.metrics // {}' 2>/dev/null)
|
|
355
|
-
if [ "$METRICS" != "{}" ] && [ "$METRICS" != "null" ]; then
|
|
356
|
-
echo "📊 METRICS"
|
|
357
|
-
echo "├─ Reliability: $(echo "$METRICS" | jq -r '.reliability // "?"' 2>/dev/null)"
|
|
358
|
-
echo "├─ Security: $(echo "$METRICS" | jq -r '.security // "?"' 2>/dev/null)"
|
|
359
|
-
echo "├─ Maintainability: $(echo "$METRICS" | jq -r '.maintainability // "?"' 2>/dev/null)"
|
|
360
|
-
echo "├─ Coverage: $(echo "$METRICS" | jq -r '.coverage // "?"' 2>/dev/null)%"
|
|
361
|
-
echo "├─ Duplications: $(echo "$METRICS" | jq -r '.duplications // "?"' 2>/dev/null)%"
|
|
362
|
-
echo "└─ Complexity: $(echo "$METRICS" | jq -r '.complexity // "?"' 2>/dev/null)"
|
|
363
|
-
echo
|
|
364
|
-
fi
|
|
365
|
-
|
|
366
|
-
# Issues Summary
|
|
367
|
-
ISSUES=$(echo "$JSON_RESPONSE" | jq -r '.issues // {}' 2>/dev/null)
|
|
368
|
-
if [ "$ISSUES" != "{}" ] && [ "$ISSUES" != "null" ]; then
|
|
369
|
-
echo "📋 ISSUES SUMMARY"
|
|
370
|
-
BLOCKER=$(echo "$ISSUES" | jq -r '.blocker // 0' 2>/dev/null)
|
|
371
|
-
CRITICAL=$(echo "$ISSUES" | jq -r '.critical // 0' 2>/dev/null)
|
|
372
|
-
MAJOR=$(echo "$ISSUES" | jq -r '.major // 0' 2>/dev/null)
|
|
373
|
-
MINOR=$(echo "$ISSUES" | jq -r '.minor // 0' 2>/dev/null)
|
|
374
|
-
INFO=$(echo "$ISSUES" | jq -r '.info // 0' 2>/dev/null)
|
|
375
|
-
TOTAL=$((BLOCKER + CRITICAL + MAJOR + MINOR + INFO))
|
|
376
|
-
|
|
377
|
-
echo "Total: $TOTAL issues found"
|
|
378
|
-
[ "$BLOCKER" -gt 0 ] && echo -e " ${RED}🔴 Blocker: $BLOCKER${NC}"
|
|
379
|
-
[ "$CRITICAL" -gt 0 ] && echo -e " ${RED}🟠 Critical: $CRITICAL${NC}"
|
|
380
|
-
[ "$MAJOR" -gt 0 ] && echo -e " ${YELLOW}🟡 Major: $MAJOR${NC}"
|
|
381
|
-
[ "$MINOR" -gt 0 ] && echo " 🔵 Minor: $MINOR"
|
|
382
|
-
[ "$INFO" -gt 0 ] && echo " ⚪ Info: $INFO"
|
|
383
|
-
echo
|
|
384
|
-
fi
|
|
385
|
-
|
|
386
|
-
# Detailed Issues
|
|
387
|
-
DETAILS_COUNT=$(echo "$JSON_RESPONSE" | jq -r '.details | length' 2>/dev/null)
|
|
388
|
-
if [ "$DETAILS_COUNT" -gt 0 ] 2>/dev/null; then
|
|
389
|
-
echo "🔍 DETAILED ISSUES"
|
|
390
|
-
echo "$JSON_RESPONSE" | jq -r '.details[]? |
|
|
391
|
-
"[\(.severity)] \(.type) in \(.file):\(.line // "?")\n \(.message)\n"' 2>/dev/null
|
|
392
|
-
fi
|
|
393
|
-
|
|
394
|
-
# Security Hotspots
|
|
395
|
-
HOTSPOTS=$(echo "$JSON_RESPONSE" | jq -r '.securityHotspots // 0' 2>/dev/null)
|
|
396
|
-
if [ "$HOTSPOTS" -gt 0 ] 2>/dev/null; then
|
|
397
|
-
echo "🔥 SECURITY HOTSPOTS: $HOTSPOTS found"
|
|
398
|
-
echo " Review security-sensitive code carefully"
|
|
384
|
+
fi
|
|
399
385
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
386
|
+
# Detailed Issues
|
|
387
|
+
DETAILS_COUNT=$(echo "$JSON_RESPONSE" | jq -r '.details | length' 2>/dev/null)
|
|
388
|
+
if [ "$DETAILS_COUNT" -gt 0 ] 2>/dev/null; then
|
|
389
|
+
echo "🔍 DETAILED ISSUES"
|
|
390
|
+
echo "$JSON_RESPONSE" | jq -r '.details[]? |
|
|
391
|
+
"[\(.severity)] \(.type) in \(.file):\(.line // "?")\n \(.message)\n"' 2>/dev/null
|
|
392
|
+
fi
|
|
393
|
+
|
|
394
|
+
# Security Hotspots
|
|
395
|
+
HOTSPOTS=$(echo "$JSON_RESPONSE" | jq -r '.securityHotspots // 0' 2>/dev/null)
|
|
396
|
+
if [ "$HOTSPOTS" -gt 0 ] 2>/dev/null; then
|
|
397
|
+
echo "🔥 SECURITY HOTSPOTS: $HOTSPOTS found"
|
|
398
|
+
echo " Review security-sensitive code carefully"
|
|
410
399
|
echo
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
400
|
+
fi
|
|
401
|
+
|
|
402
|
+
# Check if commit should be blocked
|
|
403
|
+
if [ "$QUALITY_GATE" = "FAILED" ] || [ "$APPROVED" = "false" ]; then
|
|
414
404
|
echo
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
if [ -n "$
|
|
405
|
+
error "❌ Commit blocked due to quality gate failure"
|
|
406
|
+
|
|
407
|
+
# Show blocking issues if they exist
|
|
408
|
+
if [ -n "$BLOCKING_ISSUES" ] && [ "$BLOCKING_ISSUES" != "null" ]; then
|
|
419
409
|
echo
|
|
420
|
-
echo "===
|
|
421
|
-
echo "$
|
|
422
|
-
fi
|
|
423
|
-
|
|
424
|
-
# Check if the commit should be blocked
|
|
425
|
-
if [ "$APPROVED" = "false" ]; then
|
|
426
|
-
error "❌ Commit rejected due to critical issues"
|
|
427
|
-
if [ -n "$BLOCKING_ISSUES" ] && [ "$BLOCKING_ISSUES" != "null" ]; then
|
|
428
|
-
echo
|
|
429
|
-
echo "=== CRITICAL ISSUES ==="
|
|
430
|
-
echo "$BLOCKING_ISSUES" | sed 's/^/- /'
|
|
431
|
-
|
|
432
|
-
# Generate AI-friendly resolution prompt
|
|
433
|
-
generate_resolution_prompt
|
|
434
|
-
fi
|
|
435
|
-
exit 1
|
|
410
|
+
echo "=== CRITICAL ISSUES ==="
|
|
411
|
+
echo "$BLOCKING_ISSUES" | sed 's/^/- /'
|
|
436
412
|
fi
|
|
437
413
|
|
|
438
|
-
#
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
echo
|
|
442
|
-
echo "=== ADDITIONAL DETAILS ==="
|
|
443
|
-
# If details is a string, print it directly
|
|
444
|
-
if echo "$DETAILS" | jq -e 'type == "string"' >/dev/null 2>&1; then
|
|
445
|
-
echo "$DETAILS" | jq -r '.'
|
|
446
|
-
# If it's an object or array, format it
|
|
447
|
-
else
|
|
448
|
-
echo "$DETAILS" | jq '.'
|
|
449
|
-
fi
|
|
414
|
+
# Generate AI-friendly resolution prompt if there are blocking issues
|
|
415
|
+
if [ "$BLOCKING_COUNT" -gt 0 ]; then
|
|
416
|
+
generate_resolution_prompt
|
|
450
417
|
fi
|
|
451
|
-
|
|
452
|
-
|
|
418
|
+
|
|
419
|
+
exit 1
|
|
453
420
|
fi
|
|
421
|
+
|
|
422
|
+
echo
|
|
423
|
+
log "✅ Code analysis completed. Quality gate passed."
|
|
454
424
|
|
|
455
425
|
else
|
|
456
426
|
error "Error executing Claude CLI"
|
|
File without changes
|