Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,23 @@ CodeNarc image with reviewdog.

## Test local

```
# build image
### build image

```bash
docker build -t docker.io/asaasdev/codenarc .
```

# run container

```bash
docker run --rm \
--workdir /testdata \
-e INPUT_REPORTER=local \
-e INPUT_FILTER_MODE=nofilter \
-e INPUT_FAIL_ON_ERROR=false \
-e INPUT_LEVEL=error \
-e INPUT_RULESETFILES=file:basic.xml \
-e INPUT_RULESETS_CONTENT="$(cat testdata/basic.xml)" \
-v $(pwd)/testdata:/testdata \
docker.io/asaasdev/codenarc

```
155 changes: 97 additions & 58 deletions entrypoint.sh
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 [shellcheck] reported by reviewdog 🐶
Double quote to prevent globbing and word splitting. SC2086

${INPUT_REVIEWDOG_FLAGS} || true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[shellcheck (suggestion)] reported by reviewdog 🐶

${INPUT_REVIEWDOG_FLAGS} || true

Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,32 @@ VIOLATIONS_FLAG="/tmp/found_violations.txt"
ALL_DIFF="/tmp/all_diff.txt"
CHANGED_LINES_CACHE="/tmp/changed_lines.txt"
CHANGED_FILES_CACHE="/tmp/changed_files.txt"
TMP_VIOLATIONS="/tmp/violations.tmp"

cleanup_temp_files() {
rm -f "$CODENARC_RESULT" "$LINE_VIOLATIONS" "$FILE_VIOLATIONS" "$VIOLATIONS_FLAG" \
"$ALL_DIFF" "$CHANGED_LINES_CACHE" "$CHANGED_FILES_CACHE" \
"${FILE_VIOLATIONS}.formatted" >/dev/null 2>&1
"${FILE_VIOLATIONS}.formatted" "$TMP_VIOLATIONS" >/dev/null 2>&1
}

trap 'cleanup_temp_files' EXIT

run_codenarc() {
report="${INPUT_REPORT:-compact:stdout}"
includes_arg=""

[ -n "$INPUT_SOURCE_FILES" ] && includes_arg="-includes=${INPUT_SOURCE_FILES}"

echo "🔍 Executando CodeNarc..."
java -jar /lib/codenarc-all.jar \
-report="$report" \
-rulesetfiles="${INPUT_RULESETFILES}" \
-basedir="." \
$includes_arg \
> "$CODENARC_RESULT"
$includes_arg > "$CODENARC_RESULT"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 [shellcheck] reported by reviewdog 🐶
Double quote to prevent globbing and word splitting. SC2086

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[shellcheck (suggestion)] reported by reviewdog 🐶

Suggested change
$includes_arg > "$CODENARC_RESULT"
"$includes_arg" > "$CODENARC_RESULT"


echo ""
echo "📋 Saída do CodeNarc:"
echo ""
cat "$CODENARC_RESULT"
echo ""
}

run_reviewdog_with_config() {
Expand All @@ -39,7 +43,7 @@ run_reviewdog_with_config() {
name="$4"
filter_mode="$5"
level="$6"

< "$input_file" reviewdog \
-efm="$efm" \
-reporter="$reporter" \
Expand All @@ -51,58 +55,60 @@ run_reviewdog_with_config() {
}

separate_violations() {
grep -E ':[0-9]+:' "$CODENARC_RESULT" > "$LINE_VIOLATIONS" || true
grep -E ':null:|\|\|' "$CODENARC_RESULT" > "$FILE_VIOLATIONS" || true
grep -E '^[^:]+:[0-9]+:' "$CODENARC_RESULT" > "$LINE_VIOLATIONS" || true
grep -E '^[^:]+:(null:|\|\|)' "$CODENARC_RESULT" > "$FILE_VIOLATIONS" || true
}

run_reviewdog() {
echo "📤 Enviando resultados para reviewdog..."

if ! grep -qE '^[^:]+:[0-9]+:|^[^:]+:(null:|\|\|)' "$CODENARC_RESULT"; then
return 0
fi

separate_violations

echo "📤 Enviando resultados para reviewdog..."
echo ""

if [ -s "$LINE_VIOLATIONS" ]; then
echo "📤 Enviando violações line-based (${INPUT_REPORTER:-github-pr-check})..."
run_reviewdog_with_config "$LINE_VIOLATIONS" "%f:%l:%m" \
"${INPUT_REPORTER:-github-pr-check}" "codenarc" \
"${INPUT_FILTER_MODE}" "${INPUT_LEVEL}"
fi

if [ -s "$FILE_VIOLATIONS" ]; then
true > "${FILE_VIOLATIONS}.formatted"
while read -r violation; do
if echo "$violation" | grep -q '||'; then
echo "$violation" | sed 's/||/::/'
echo "$violation" | sed 's/||/::/g'
else
echo "$violation" | sed 's/:null:/::/'
echo "$violation" | sed 's/:null:/::/g'
fi
done < "$FILE_VIOLATIONS" > "${FILE_VIOLATIONS}.formatted"

if [ "${INPUT_REPORTER}" = "local" ]; then
echo "📤 Enviando violações file-based (local)..."
run_reviewdog_with_config "${FILE_VIOLATIONS}.formatted" "%f::%m" \
"local" "codenarc" "nofilter" "${INPUT_LEVEL}"
else
echo "📤 Enviando violações file-based (github-pr-check)..."
run_reviewdog_with_config "${FILE_VIOLATIONS}.formatted" "%f::%m" \
"github-pr-check" "codenarc" "nofilter" "warning"
fi
fi

# fallback se nao houver violacoes categorizadas
if [ ! -s "$LINE_VIOLATIONS" ] && [ ! -s "$FILE_VIOLATIONS" ]; then
echo "📝 Executando reviewdog padrão..."
run_reviewdog_with_config "$CODENARC_RESULT" "%f:%l:%m" \
"${INPUT_REPORTER:-github-pr-check}" "codenarc" \
"${INPUT_FILTER_MODE}" "${INPUT_LEVEL}"
fi
}

generate_git_diff() {
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
echo "⚠️ Diretório não é um repositório Git; nenhuma comparação de diff será feita."
return 0
fi

if [ -n "$GITHUB_BASE_SHA" ] && [ -n "$GITHUB_HEAD_SHA" ]; then
git fetch origin "$GITHUB_BASE_SHA" --depth=1 2>/dev/null || true
git fetch origin "$GITHUB_HEAD_SHA" --depth=1 2>/dev/null || true
git diff -U0 "$GITHUB_BASE_SHA" "$GITHUB_HEAD_SHA" -- '*.groovy'
else
if ! git rev-parse HEAD~1 >/dev/null 2>&1; then
echo "⚠️ Nenhum commit anterior para comparar; diff vazio."
return 0
fi
git diff -U0 HEAD~1 -- '*.groovy'
fi
}
Expand All @@ -119,10 +125,13 @@ parse_diff_range() {
build_changed_lines_cache() {
true > "$CHANGED_LINES_CACHE"
true > "$CHANGED_FILES_CACHE"

generate_git_diff > "$ALL_DIFF" 2>/dev/null || true
[ ! -s "$ALL_DIFF" ] && return 0

[ ! -s "$ALL_DIFF" ] && {
echo "ℹ️ Nenhum diff detectado; prosseguindo com cache vazio."
return 0
}

current_file=""
while read -r line; do
case "$line" in
Expand All @@ -136,10 +145,10 @@ build_changed_lines_cache() {
range_info=$(parse_diff_range "$range")
start=$(echo "$range_info" | cut -d' ' -f1)
count=$(echo "$range_info" | cut -d' ' -f2)

case "$start" in ''|*[!0-9]*) continue ;; esac
case "$count" in ''|*[!0-9]*) continue ;; esac

i="$start"
while [ "$i" -lt "$((start + count))" ]; do
echo "$current_file:$i" >> "$CHANGED_LINES_CACHE"
Expand All @@ -150,6 +159,25 @@ build_changed_lines_cache() {
done < "$ALL_DIFF"
}

get_rule_priority() {
rule_name="$1"
priority=$(echo "$INPUT_RULESETS_CONTENT" | grep -B 2 "name='$rule_name'" | grep -o 'priority" value="[0-9]' | head -1 | cut -d'"' -f3)
if [ -z "$priority" ]; then
priority=$(echo "$INPUT_RULESETS_CONTENT" | grep "class='[^']*${rule_name}Rule'" -A 5 | grep -o 'priority" value="[0-9]' | head -1 | cut -d'"' -f3)
fi
if [ -z "$priority" ]; then
priority=$(echo "$INPUT_RULESETS_CONTENT" | grep "class='[^']*${rule_name}'" -A 5 | grep -o 'priority" value="[0-9]' | head -1 | cut -d'"' -f3)
fi
if [ -z "$priority" ]; then
priority=$(echo "$INPUT_RULESETS_CONTENT" | grep -A 3 "path='[^']*${rule_name}" | grep -o 'priority" value="[0-9]' | head -1 | cut -d'"' -f3)
fi
echo "${priority:-2}"
}

extract_rule_name() {
echo "$1" | sed -E 's/^[^:]+:[^:]+:([A-Za-z0-9]+).*/\1/'
}

get_p1_count() {
p1_count=$(grep -Eo "p1=[0-9]+" "$CODENARC_RESULT" | cut -d'=' -f2 | head -1)
echo "${p1_count:-0}"
Expand All @@ -162,9 +190,7 @@ get_allowed_patterns() {
file_matches_patterns() {
file="$1"
patterns="$2"

[ -z "$patterns" ] && return 0

for pattern in $patterns; do
echo "$file" | grep -Eq "$pattern" && return 0
done
Expand All @@ -181,48 +207,61 @@ is_file_changed() {

check_blocking_rules() {
echo "🔎 Verificando violações bloqueantes (priority 1)..."

[ ! -f "$CODENARC_RESULT" ] && echo "❌ Resultado não encontrado" && return 1

p1_count=$(get_p1_count)
echo "📊 Total de P1 encontradas: $p1_count"

[ "$p1_count" -eq 0 ] && echo "✅ Nenhuma P1 detectada → merge permitido" && return 0

echo "⚠️ Verificando P1s em linhas alteradas..."
if [ "$p1_count" -eq 0 ]; then
echo "✅ Nenhuma violação P1 detectada"
echo ""
return 0
fi

echo "📊 Violações P1 nos arquivos analisados: ${p1_count:-0}"
echo "⚙️ Analisando diff para identificar P1 em linhas/arquivos alterados..."
build_changed_lines_cache

allowed_patterns=$(get_allowed_patterns)
[ -n "$allowed_patterns" ] && echo "🧩 Analisando apenas arquivos filtrados por INPUT_SOURCE_FILES"
[ -n "$allowed_patterns" ] && echo "🧩 Aplicando filtro de arquivos: INPUT_SOURCE_FILES"

echo "0" > "$VIOLATIONS_FLAG"

grep -E ':[0-9]+:|:null:|\|\|' "$CODENARC_RESULT" | while IFS=: read -r file line rest; do
p1_in_diff=0
grep -E '^[^:]+:[0-9]+:|^[^:]+:(null:|\|\|)' "$CODENARC_RESULT" > "$TMP_VIOLATIONS" || true

while IFS=: read -r file line rest; do
[ -z "$file" ] && continue
if echo "$file" | grep -q '||'; then
file=$(echo "$file" | cut -d'|' -f1)
line=""
fi
[ -z "$file" ] && continue
file_matches_patterns "$file" "$allowed_patterns" || continue

rule_name=$(extract_rule_name "$file:$line:$rest")
priority=$(get_rule_priority "$rule_name")
[ "$priority" != "1" ] && continue

if [ -z "$line" ] || [ "$line" = "null" ]; then
if is_file_changed "$file"; then
echo "📍 Violação file-based em arquivo alterado: $file"
echo "1" > "$VIOLATIONS_FLAG" && break
p1_in_diff=$((p1_in_diff + 1))
echo " ⛔ P1 #$p1_in_diff: $rule_name (file-based) em $file"
echo "1" > "$VIOLATIONS_FLAG"
fi
elif is_line_changed "$line" "$file"; then
echo "📍 Violação em linha alterada: $file:$line"
echo "1" > "$VIOLATIONS_FLAG" && break
p1_in_diff=$((p1_in_diff + 1))
echo " ⛔ P1 #$p1_in_diff: $rule_name na linha $line de $file"
echo "1" > "$VIOLATIONS_FLAG"
fi
done

done < "$TMP_VIOLATIONS"

rm -f "$TMP_VIOLATIONS"
echo ""
if [ "$(cat "$VIOLATIONS_FLAG")" -eq 1 ]; then
echo "⛔ P1s existem E há violações em linhas alteradas"
echo "💡 Corrija as violacoes ou use o bypass autorizado pelo coordenador."
echo "❌ BLOQUEIO: $p1_in_diff violação(ões) P1 encontrada(s) em linhas/arquivos alterados do PR"
echo "💡 Corrija as violações acima ou utilize o bypass autorizado"
exit 1
else
echo "✅ P1s existem mas fora das linhas alteradas → merge permitido"
p1_outside_diff=$((p1_count - p1_in_diff))
echo "✅ APROVADO: Nenhuma violação P1 em linhas/arquivos alterados do PR"
[ "$p1_outside_diff" -gt 0 ] && echo "ℹ️ ${p1_outside_diff} violação(ões) P1 em código não modificado (não bloqueia)"
fi
echo ""
}

if [ -n "${GITHUB_WORKSPACE}" ]; then
Expand All @@ -236,4 +275,4 @@ run_codenarc
run_reviewdog
check_blocking_rules

echo "🏁 Concluído com sucesso"
echo "🏁 Concluído com sucesso"
Loading
Loading