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
18 changes: 18 additions & 0 deletions gh-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,24 @@ joshjohanning-org/.github, no code scanning results

Gets the commits of since a certain date - date should be in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format, ie: `since=2022-03-28T16:00:49Z`

### get-copilot-ai-credit-usage-by-user-and-model.sh

Exports monthly Copilot AI-credit usage by user and model for an enterprise.
The script first uses daily per-user metrics to identify users with AI-credit
usage, then makes one billing API call per identified user.

```shell
./get-copilot-ai-credit-usage-by-user-and-model.sh <enterprise> [year] [month] [output.csv] [max-users]
```

The script uses the current `gh auth` credential. Classic PAT authentication
may require `read:enterprise` and `manage_billing:copilot`.

> [!WARNING]
> The model breakdown endpoint only accepts one user filter at a time. Large
> enterprises can require thousands of API calls and may approach the API rate
> limit. Use the optional `max-users` argument for testing.

### get-dependencies-in-repository.sh

Gets dependencies used in the repository, including the ecosystem and version number.
Expand Down
132 changes: 132 additions & 0 deletions gh-cli/get-copilot-ai-credit-usage-by-user-and-model.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#!/usr/bin/env bash
# Export monthly enterprise AI credit usage grouped by user and model.
# Usage: get-copilot-ai-credit-usage-by-user-and-model.sh <enterprise> [year] [month] [output.csv] [max-users]
# Requires authenticated gh access to Copilot metrics and billing plus jq and curl.
set -euo pipefail

usage() {
echo "Usage: $0 <enterprise> [year] [month] [output.csv] [max-users]" >&2
}

fail() {
echo "Error: $*" >&2
exit 1
}

api() {
local error_file output
error_file=$(mktemp)
TEMP_FILES+=("$error_file")

if ! output=$(gh api "$@" 2>"$error_file"); then
cat "$error_file" >&2
if grep -q "HTTP 404" "$error_file"; then
cat >&2 <<'EOF'

The API returned 404. Confirm the enterprise slug and credential access.
For classic PAT authentication, try:
gh auth refresh -s read:enterprise -s manage_billing:copilot

The metrics API also requires the enterprise Copilot usage metrics policy.
The enterprise AI credit endpoint may require an enterprise owner or billing
manager using a classic PAT.
EOF
fi
return 1
fi

printf '%s' "$output"
}

days_in_month() {
case "$1" in
1|3|5|7|8|10|12) echo 31 ;;
4|6|9|11) echo 30 ;;
2)
if (( YEAR % 400 == 0 || (YEAR % 4 == 0 && YEAR % 100 != 0) )); then
echo 29
else
echo 28
fi
;;
*) fail "Month must be between 1 and 12." ;;
esac
}

[[ $# -ge 1 && $# -le 5 ]] || { usage; exit 1; }
for command_name in gh jq curl; do
command -v "$command_name" >/dev/null 2>&1 ||
fail "Required command not found: $command_name"
done
gh auth status >/dev/null 2>&1 ||
fail "GitHub CLI is not authenticated. Run: gh auth login"

ENTERPRISE="$1"
YEAR="${2:-$(date +%Y)}"
MONTH=$((10#${3:-$(date +%m)}))
[[ "$YEAR" =~ ^[0-9]{4}$ ]] || fail "Year must use YYYY format."

MONTH_PADDED=$(printf '%02d' "$MONTH")
OUTPUT="${4:-${ENTERPRISE}-copilot-ai-credit-usage-${YEAR}-${MONTH_PADDED}.csv}"
MAX_USERS="${5:-0}"
[[ "$MAX_USERS" =~ ^[0-9]+$ ]] || fail "Max users must be a non-negative integer."

ACTIVE_USERS=$(mktemp)
TEMP_FILES=("$ACTIVE_USERS")
trap 'rm -f "${TEMP_FILES[@]}"' EXIT

LAST_DAY=$(days_in_month "$MONTH")
echo "Finding users with AI-credit usage in $YEAR-$MONTH_PADDED..." >&2

for ((day = 1; day <= LAST_DAY; day++)); do
report_date=$(printf '%04d-%02d-%02d' "$YEAR" "$MONTH" "$day")
echo "Reading $report_date..." >&2
api -H "X-GitHub-Api-Version: 2026-03-10" \
"/enterprises/$ENTERPRISE/copilot/metrics/reports/users-1-day?day=$report_date" |
jq -r 'if type == "object" then (.download_links // [])[] else empty end' |
while IFS= read -r url; do
[[ -n "$url" ]] || continue
curl -fsSL "$url" |
jq -r 'select(type == "object" and (.ai_credits_used // 0) > 0) | .user_login'
done
done | sort -u >"$ACTIVE_USERS"

user_count=$(wc -l <"$ACTIVE_USERS" | tr -d ' ')
if (( MAX_USERS > 0 && user_count > MAX_USERS )); then
head -n "$MAX_USERS" "$ACTIVE_USERS" >"${ACTIVE_USERS}.limited"
mv "${ACTIVE_USERS}.limited" "$ACTIVE_USERS"
user_count="$MAX_USERS"
fi

echo "Found $user_count users. This next phase makes one billing API call per user." >&2
if (( user_count > 1000 )); then
echo "Warning: this may approach the 5,000 requests/hour classic PAT limit." >&2
fi

{
echo '"user","model","gross_ai_credits","included_ai_credits","net_ai_credits","gross_amount","net_spend"'
while IFS= read -r login; do
[[ -n "$login" ]] || continue
echo "Processing $login..." >&2
api --method GET -H "X-GitHub-Api-Version: 2026-03-10" \
"/enterprises/$ENTERPRISE/settings/billing/ai_credit/usage" \
-f year="$YEAR" -f month="$MONTH" -f user="$login" |
jq -r --arg user "$login" '
.usageItems
| select(type == "array" and length > 0)
| group_by(.model)[]
| [
$user,
.[0].model,
(map(.grossQuantity) | add),
(map(.discountQuantity) | add),
(map(.netQuantity) | add),
(map(.grossAmount) | add),
(map(.netAmount) | add)
]
| @csv
'
done <"$ACTIVE_USERS"
} >"$OUTPUT"

echo "Created $OUTPUT" >&2
4 changes: 4 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ Migrate work items from Azure DevOps to GitHub issues - this just links out to a

See: [code-scanning-coverage-report](./code-scanning-coverage-report/README.md)

## copilot-enterprise-usage-report

See: [copilot-enterprise-usage-report](./copilot-enterprise-usage-report/README.md)

## create-app-jwt.py

This script will generate a JWT for a GitHub App. It will use the private key and app ID from the GitHub App's settings page.
Expand Down
48 changes: 48 additions & 0 deletions scripts/copilot-enterprise-usage-report/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# copilot-enterprise-usage-report

Generate monthly GitHub Copilot enterprise usage reports from the current
`enterprise-1-day` Usage Metrics API.

## Outputs

- Weekly surface activity CSV
- Standalone HTML report with embedded data

The report distinguishes unlike metrics instead of treating them as equivalent:

- IDEs expose user-initiated interactions and generation activity
- Copilot CLI and Copilot App expose prompt and request counts
- Copilot Coding Agent exposes Copilot-created pull requests
- Copilot Code Review exposes Copilot-reviewed pull requests

## Prerequisites

- An authenticated GitHub CLI session: `gh auth status`
- `jq`, `curl`, and `base64`
- Enterprise access to Copilot usage metrics

Classic PATs need `read:enterprise` or `manage_billing:copilot`. Fine-grained
credentials need the **View Enterprise Copilot Metrics** permission. The
enterprise **Copilot usage metrics** policy must also be enabled.

## Usage

```shell
./copilot-enterprise-usage-report.sh <enterprise> [year] [month] [output-prefix]
```

Example:

```shell
./copilot-enterprise-usage-report.sh avocado-corp 2026 7
```

This creates:

```text
avocado-corp-copilot-usage-2026-07-weekly.csv
avocado-corp-copilot-usage-2026-07.html
```

The API provides up to one year of daily history beginning October 10, 2025.
Recent data can take several UTC days to finalize.
Loading