Skip to content

Reporting & analytics with jq

The Scripting guide lists three starter jq patterns. This recipe expands that into a small analytics toolkit you can paste into a weekly report job.

All recipes assume:

Terminal window
WORKSPACE=myworkspace
REPO=myrepo

bb pr list only returns one state at a time, so to count across all states fetch each separately and combine:

Terminal window
for state in OPEN MERGED DECLINED SUPERSEDED; do
count=$(bb pr list -w "$WORKSPACE" -r "$REPO" -s "$state" --json --jq '.count')
printf "%-12s %s\n" "$state" "$count"
done

Sample output:

OPEN 12
MERGED 340
DECLINED 8
SUPERSEDED 2

If you only need a snapshot of currently open PRs grouped by state attribute, a one-liner suffices:

Terminal window
bb pr list -w "$WORKSPACE" -r "$REPO" --json --jq '
.pullRequests
| group_by(.state)
| map({ state: .[0].state, count: length })
'

pr list does not include diff stats — they come from bb pr diff <id> --json --stat (or equivalent). For aggregate volume, walk every PR and sum:

#!/bin/bash
total_added=0
total_deleted=0
for pr_id in $(bb pr list -w "$WORKSPACE" -r "$REPO" -s MERGED --json \
--jq '.pullRequests[].id'); do
stats=$(bb pr diff "$pr_id" -w "$WORKSPACE" -r "$REPO" --stat --json)
added=$(echo "$stats" | jq '[.files[].additions] | add // 0')
deleted=$(echo "$stats" | jq '[.files[].deletions] | add // 0')
total_added=$(( total_added + added ))
total_deleted=$(( total_deleted + deleted ))
sleep 1
done
echo "Total added: $total_added"
echo "Total deleted: $total_deleted"
Terminal window
bb pr list -w "$WORKSPACE" -r "$REPO" --json --jq '
.pullRequests
| group_by(.author.nickname // .author.display_name)
| map({
author: (.[0].author.nickname // .[0].author.display_name),
count: length,
ids: [.[].id]
})
| sort_by(-.count)
'

This sorts authors by descending PR count and includes the IDs for drilldown.

Useful for identifying review load. Iterates over merged PRs and counts approvals per reviewer:

Terminal window
bb pr list -w "$WORKSPACE" -r "$REPO" -s MERGED --limit 200 --json --jq '
[
.pullRequests[].participants[]
| select(.approved == true)
| .user.nickname // .user.display_name
]
| group_by(.)
| map({ reviewer: .[0], approvals: length })
| sort_by(-.approvals)
'

To export an open-PRs report into a spreadsheet, use jq’s @csv:

Terminal window
bb pr list -w "$WORKSPACE" -r "$REPO" --limit 500 --json --jq '
["id","title","author","state","created_on","source","destination"],
(
.pullRequests[]
| [
.id,
.title,
(.author.nickname // .author.display_name),
.state,
.created_on,
.source.branch.name,
.destination.branch.name
]
)
| @csv
' > prs.csv
head -3 prs.csv

Sample output:

"id","title","author","state","created_on","source","destination"
42,"Add login button","alice","OPEN","2025-01-04T09:11:00Z","feat/login","main"
43,"Fix typo in README","bob","OPEN","2025-01-04T11:22:00Z","fix/typo","main"
Terminal window
bb pr list -w "$WORKSPACE" -r "$REPO" -s MERGED --limit 100 --json --jq '
[
.pullRequests[]
| {
id,
title,
hours: (
(.updated_on | fromdateiso8601)
- (.created_on | fromdateiso8601)
) / 3600
}
]
| sort_by(.hours)
'

updated_on on a merged PR approximates the merge time; for exact merge time, walk bb pr activity <id> and find the merge event.