Skip to content
Merged
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
27 changes: 24 additions & 3 deletions .agents/scripts/gh-failure-miner-helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,19 @@
local checks_json
checks_json=$(gh api "repos/${repo_slug}/commits/${head_sha}/check-runs?per_page=100" 2>/dev/null || printf '{"check_runs":[]}')

# Filter check runs for failures. Two-pass approach:
# 1. Hard failures (failure, cancelled, timed_out, startup_failure) — always collected
# 2. action_required — only from GitHub Actions runs. External apps (Codacy, SonarCloud)
# use action_required to mean "issues found for developer review", which is informational
# not a CI failure. Including these creates false systemic clusters (GH#4696).
local failed_runs_json
failed_runs_json=$(printf '%s\n' "$checks_json" | jq '[.check_runs[] | select((.conclusion // "" | ascii_downcase) as $c | ["failure","cancelled","timed_out","action_required","startup_failure"] | index($c))]')
failed_runs_json=$(printf '%s\n' "$checks_json" | jq '[.check_runs[] | select(
((.conclusion // "" | ascii_downcase) as $c |
["failure","cancelled","timed_out","startup_failure"] | index($c))
or
((.conclusion // "" | ascii_downcase) == "action_required"
and (.app.slug // "" | ascii_downcase) == "github-actions")
)]')
Comment on lines +292 to +298

Choose a reason for hiding this comment

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

medium

The jq filter can be made more readable and efficient. By defining conclusion as a variable c at a higher scope within the jq expression, you can avoid repeating (.conclusion // "" | ascii_downcase) and make the logic clearer.

Suggested change
failed_runs_json=$(printf '%s\n' "$checks_json" | jq '[.check_runs[] | select(
((.conclusion // "" | ascii_downcase) as $c |
["failure","cancelled","timed_out","startup_failure"] | index($c))
or
((.conclusion // "" | ascii_downcase) == "action_required"
and (.app.slug // "" | ascii_downcase) == "github-actions")
)]')
failed_runs_json=$(printf '%s\n' "$checks_json" | jq '[.check_runs[] |
(.conclusion // "" | ascii_downcase) as $c |
select(
(["failure","cancelled","timed_out","startup_failure"] | index($c))
or
($c == "action_required" and (.app.slug // "" | ascii_downcase) == "github-actions")
)
]')


local failed_count
failed_count=$(printf '%s\n' "$failed_runs_json" | jq 'length')
Expand All @@ -306,10 +317,20 @@
local run_id
run_id=$(parse_run_id_from_details_url "$details_url")

local signature="not_collected"
if [[ "$include_logs" == "true" ]] && [[ -n "$run_id" ]] && [[ "$run_logs_checked" -lt "$max_run_logs" ]]; then
# For non-GitHub-Actions check runs (e.g., Codacy, SonarCloud), the details_url
# points to the external app, not a GH Actions run — so run_id is empty and logs
# can't be extracted. Use the conclusion as the signature instead of "not_collected"
# to produce meaningful cluster grouping (GH#4696).
local signature
if [[ -z "$run_id" ]]; then
local app_name
app_name=$(printf '%s\n' "$run_json" | jq -r '.app.name // "external"')
signature="${conclusion}:${app_name}"
elif [[ "$include_logs" == "true" ]] && [[ "$run_logs_checked" -lt "$max_run_logs" ]]; then
signature=$(extract_failure_signature "$repo_slug" "$run_id")
run_logs_checked=$((run_logs_checked + 1))
else
signature="not_collected"
fi

jq -n \
Expand Down Expand Up @@ -549,7 +570,7 @@
local existing_count
existing_count=$(gh issue list --repo "$repo_slug" --state open --search "\"${signal_tag}\" in:body" --json number --limit 1 2>/dev/null | jq 'length') || existing_count=0
if [[ "$existing_count" -gt 0 ]]; then
echo "Skipping cluster for ${check_name} - existing open issue with ${signal_tag}"

Check warning on line 573 in .agents/scripts/gh-failure-miner-helper.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of using the literal 'length' 4 times.

See more on https://sonarcloud.io/project/issues?id=marcusquinn_aidevops&issues=AZzrTdLOh1oMZE21iH4e&open=AZzrTdLOh1oMZE21iH4e&pullRequest=4704
idx=$((idx + 1))
continue
fi
Expand Down
6 changes: 4 additions & 2 deletions .codacy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
#
# Reference: https://docs.codacy.com/repositories-configure/codacy-configuration-file/
#
# Root cause context (GH#4346):
# Root cause context (GH#4346, GH#4696):
# - Codacy flagged SC2086 (unquoted variable) in code that was being REMOVED by a PR fix.
# - Codacy also returned "not_collected" on a transient service issue.
# - "not_collected" reports were a failure-miner misclassification, not a Codacy issue.
# Codacy's action_required conclusion (= "issues found") was treated as a CI failure
# by gh-failure-miner-helper.sh. Fixed in GH#4696.
# - This config excludes archived/ (same as CI shellcheck) and aligns tool settings.

---
Expand Down
25 changes: 12 additions & 13 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,32 +175,31 @@ jobs:
echo "::warning::SONAR_TOKEN not configured — skipping SonarCloud scan"
echo "Add SONAR_TOKEN to repository secrets to enable SonarCloud analysis"

- name: Codacy Analysis
- name: Codacy Integration Check
# Codacy analysis runs via the Codacy Production GitHub App (not this workflow).
# This step only verifies the API token is configured for Codacy API access.
# The "Codacy Static Code Analysis" check run is posted by the Codacy App
# independently on each PR commit.
run: |
if [[ -n "$CODACY_API_TOKEN" ]]; then
echo "Codacy Analysis Status..."
echo "Codacy API Token: Configured"
echo "Repository monitored at: https://app.codacy.com/gh/marcusquinn/aidevops"
echo "Codacy integration: Active"
echo "Codacy API token: configured"
echo "Codacy GitHub App: runs analysis independently on PRs"
echo "Dashboard: https://app.codacy.com/gh/marcusquinn/aidevops"
else
echo "::notice::Codacy API token not configured, skipping analysis"
echo "Add CODACY_API_TOKEN to repository secrets to enable Codacy analysis"
echo "::notice::CODACY_API_TOKEN not configured — Codacy API access unavailable"
echo "Note: Codacy GitHub App analysis still runs if the app is installed"
fi

- name: Quality Analysis Summary
run: |
echo "Code Quality Analysis Summary"
echo "================================"
if [[ -n "$SONAR_TOKEN" ]]; then
echo "SonarCloud: Analysis completed"
echo "SonarCloud: Analysis completed (via workflow action)"
else
echo "SonarCloud: Skipped (SONAR_TOKEN not configured)"
fi
if [[ -n "$CODACY_API_TOKEN" ]]; then
echo "Codacy: Analysis completed"
else
echo "Codacy: Skipped (token not configured)"
fi
echo "Codacy: Runs via GitHub App (independent of this workflow)"
echo ""
echo "View Results:"
echo " SonarCloud: https://sonarcloud.io/project/overview?id=marcusquinn_aidevops"
Expand Down
Loading