feat: add summary header to find-api-calls.sh

Without an overview the script dumps thousands of file:line: matches
across many sections, leaving the reader to figure out which framework
even applies. A short summary at the top makes the rest of the output
actionable.

The summary counts hits per framework / DI / auth-signal category in a
single grep pass over the source tree (8 separate greps would have
roughly octupled the runtime on a large decompile). Output is a 3-line
table:

  HTTP framework:   Retrofit=N OkHttp=N Ktor=N Apollo=N Volley=N
  DI framework:     Hilt/Dagger=N Koin=N
  Auth signals:     Bearer=N HMAC/Sign=N

A reader can immediately see which framework the app actually uses,
whether auth is bearer-token or signed, and whether to spend time on a
section or skip it. The summary is suppressed when a single section flag
(--retrofit, --ktor, --paths, ...) is given, so the existing single-section
workflows are unchanged.

A reminder of the available section flags is printed below the counts
so the agent does not have to consult --help.
This commit is contained in:
Michał Tajchert 2026-04-29 01:39:55 +02:00
parent ec2b14c171
commit 627889a4c6
1 changed files with 52 additions and 0 deletions

View File

@ -82,6 +82,58 @@ run_grep() {
grep $GREP_OPTS -E "$pattern" "$SOURCE_DIR" 2>/dev/null || true
}
# Print a one-screen summary FIRST so a reader knows what to expect from
# the long output that follows. Skipped when a single section flag was
# requested (the user wants raw matches, not an overview). One pass over
# the tree, counts bucketed by tag — running 8 separate greps was too slow.
if [[ "$SEARCH_ALL" == true ]]; then
section "Summary (counted in a single pass)"
declare -A H=(
[retrofit]=0 [okhttp]=0 [ktor]=0 [apollo]=0 [volley]=0
[hilt]=0 [koin]=0 [bearer]=0 [hmac]=0
)
while IFS= read -r line; do
case "$line" in
*"@GET("*|*"@POST("*|*"@PUT("*|*"@DELETE("*|*"@PATCH("*|*"@HTTP("*) H[retrofit]=$((H[retrofit]+1));;
esac
case "$line" in
*"Request.Builder"*|*"HttpUrl"*|*".newCall("*) H[okhttp]=$((H[okhttp]+1));;
esac
case "$line" in
*"BearerTokens"*|*"defaultRequest {"*|*"client.get("*|*"client.post("*|*"httpClient.get("*|*"httpClient.post("*|*"HttpClient.get("*) H[ktor]=$((H[ktor]+1));;
esac
case "$line" in
*"ApolloClient"*|*".serverUrl("*) H[apollo]=$((H[apollo]+1));;
esac
case "$line" in
*"StringRequest"*|*"JsonObjectRequest"*|*"RequestQueue"*) H[volley]=$((H[volley]+1));;
esac
case "$line" in
*"@HiltAndroidApp"*|*"@AndroidEntryPoint"*|*"@HiltViewModel"*|*"@Provides"*|*"@Binds"*) H[hilt]=$((H[hilt]+1));;
esac
case "$line" in
*"org.koin."*|*"module {"*|*"single<"*|*"factory<"*|*"singleOf("*|*"factoryOf("*) H[koin]=$((H[koin]+1));;
esac
case "$line" in
*'"Bearer '*|*'"bearer '*|*"BearerTokens"*) H[bearer]=$((H[bearer]+1));;
esac
case "$line" in
*"HmacSHA"*|*'Mac.getInstance("Hmac'*) H[hmac]=$((H[hmac]+1));;
esac
done < <(grep -rEh --include='*.java' --include='*.kt' \
'@(GET|POST|PUT|DELETE|PATCH|HTTP)\(|Request\.Builder|HttpUrl|\.newCall\(|BearerTokens|defaultRequest \{|client\.(get|post)\(|httpClient\.(get|post)\(|ApolloClient|\.serverUrl\(|StringRequest|JsonObjectRequest|RequestQueue|@HiltAndroidApp|@AndroidEntryPoint|@HiltViewModel|@Provides|@Binds|org\.koin\.|module \{|single<|factory<|"[Bb]earer |HmacSHA|Mac\.getInstance' \
"$SOURCE_DIR" 2>/dev/null || true)
printf ' HTTP framework: Retrofit=%-5s OkHttp=%-5s Ktor=%-5s Apollo=%-5s Volley=%-5s\n' \
"${H[retrofit]}" "${H[okhttp]}" "${H[ktor]}" "${H[apollo]}" "${H[volley]}"
printf ' DI framework: Hilt/Dagger=%-5s Koin=%-5s\n' \
"${H[hilt]}" "${H[koin]}"
printf ' Auth signals: Bearer=%-5s HMAC/Sign=%-5s\n' \
"${H[bearer]}" "${H[hmac]}"
echo
echo " Run with one of --retrofit / --okhttp / --ktor / --apollo / --volley /"
echo " --paths / --urls / --auth to inspect a single section."
fi
# --- Retrofit ---
if [[ "$SEARCH_ALL" == true || "$SEARCH_RETROFIT" == true ]]; then
section "Retrofit Annotations"