master
sh 75 lines 2.89 KB
Raw
1 #!/usr/bin/env bash
2 # Fetch SonarCloud findings introduced by a specific pull request.
3 #
4 # Usage:
5 # fetch-sonar-findings.sh <pr-number>
6 #
7 # SonarCloud does NOT post per-finding inline comments on the GitHub PR --
8 # only a QualityGate summary comment is delivered. The actual issue list
9 # lives behind /api/issues/search?pullRequest=<N> and /api/hotspots/search.
10 # This script pulls both, so the PR-reviews loop can address them.
11 #
12 # Outputs (under .local/audits/pr-reviews/pr-<N>/):
13 # sonar-issues.json -- all open issues this PR introduced
14 # sonar-hotspots.json -- all open security hotspots this PR introduced
15 #
16 # Reads SONAR_TOKEN, SONAR_HOST_URL, SONAR_PROJECT from <repo-root>/.env --
17 # the same .env entries the sonarqube-audit skill uses. If they're missing,
18 # this script prints what's needed and exits 1.
19 #
20 # Sourcing strategy: this script is part of pr-reviews, but it leans on
21 # the sonarqube-audit skill's `_lib.sh` helpers (sq_load_env, sq_paginate)
22 # so we get a single paginator + token-masking implementation, rather
23 # than duplicating the loop and risking drift.
24
25 set -euo pipefail
26
27 # shellcheck source=./_lib.sh
28 # shellcheck disable=SC1091
29 source "$(dirname "$0")/_lib.sh"
30
31 # shellcheck disable=SC1091
32 source "$(dirname "$0")/../../sonarqube-audit/scripts/_lib.sh"
33
34 PR="${1:?usage: $0 <pr-number>}"
35 pr_require_numeric "${PR}"
36
37 # sq_load_env reads <repo-root>/.env; same .env the pr-reviews scripts use.
38 sq_load_env
39
40 DIR="$(pr_state_dir "${PR}")"
41
42 echo -e "${PR_GRAY}[fetch-sonar] PR ${PR} -> ${DIR}${PR_NC}" >&2
43
44 # Build per-source path. sq_paginate streams one JSON page per line; jq -s
45 # slurps them and concatenates the array under each result key.
46 sq_paginate "/api/issues/search?componentKeys=${SONAR_PROJECT}&pullRequest=${PR}&resolved=false" \
47 | jq -s '[.[].issues[]]' > "${DIR}/sonar-issues.json"
48
49 sq_paginate "/api/hotspots/search?projectKey=${SONAR_PROJECT}&pullRequest=${PR}&status=TO_REVIEW" \
50 | jq -s '[.[].hotspots[]]' > "${DIR}/sonar-hotspots.json"
51
52 # Summary
53 n_issues="$(jq 'length' "${DIR}/sonar-issues.json")"
54 n_hotspots="$(jq 'length' "${DIR}/sonar-hotspots.json")"
55
56 echo
57 echo "SonarCloud findings on PR ${PR}:"
58 echo " issues: ${n_issues}"
59 echo " hotspots: ${n_hotspots}"
60 echo
61 if (( n_issues > 0 )); then
62 echo "Issues by severity / rule:"
63 jq -r 'group_by(.severity + " " + .rule) | .[] | " \(.[0].severity) \(.[0].rule) x\(length)"' \
64 "${DIR}/sonar-issues.json"
65 echo
66 echo "Issue details:"
67 jq -r '.[] | " \(.key) \(.severity) \(.rule) \(.component | sub("^[^:]+:"; ""))\(if .line then ":" + (.line | tostring) else "" end)\n \(.message)"' \
68 "${DIR}/sonar-issues.json"
69 fi
70 if (( n_hotspots > 0 )); then
71 echo
72 echo "Hotspots:"
73 jq -r '.[] | " \(.key) \(.vulnerabilityProbability) \(.ruleKey) \(.component | sub("^[^:]+:"; ""))\(if .line then ":" + (.line | tostring) else "" end)\n \(.message)"' \
74 "${DIR}/sonar-hotspots.json"
75 fi