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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ runner's busy state to `/var/log/ci-load.tsv` (35 days kept). `host/ci-load-repo
summary every Monday at 13:00 UTC, from alerts@ericdahl.dev through the `mail-bridge` container
(ger3 blocks outbound SMTP). Its settings are in `/etc/ci-load-report.env` (root only:
`MAIL_BRIDGE_SMTP_PASSWORD` from Doppler `ericdahl-dev/prd`, and `REPORT_TO`). Cron:
`/etc/cron.d/ci-load-report`, log `/var/log/ci-load-report.log`.
`/etc/cron.d/ci-load-report`, log `/var/log/ci-load-report.log`. With `GH_BILLING_PAT` in the env file
(fine-grained, org Administration: read, Doppler `GH_BILLING_PAT`) the email also shows private-repo
GitHub-hosted minutes for the month against the 3,000 included.

## Setup facts and workflow rules

Expand Down
27 changes: 26 additions & 1 deletion host/ci-load-report.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
# Mondays: email a 7-day summary of ger3 load and runner use, from the samples
# ci-load-sample collects. Mail goes through the mail-bridge on the coolify network
# (ger3 blocks outbound SMTP). Needs /etc/ci-load-report.env (root, 600) with
# MAIL_BRIDGE_SMTP_PASSWORD and REPORT_TO.
# MAIL_BRIDGE_SMTP_PASSWORD and REPORT_TO, and optionally GH_BILLING_PAT (fine-grained,
# org Administration: read) to add GitHub-hosted Actions minutes for the month.
# Installed as /usr/local/bin/ci-load-report, cron in /etc/cron.d/ci-load-report.
set -eu
. /etc/ci-load-report.env
Expand Down Expand Up @@ -30,6 +31,30 @@ summary=$(awk -v s="$since" -v cores="$CORES" '
printf "sits above the core count, revisit runner count or limits.\n"
}' "$LOG")

if [ -n "${GH_BILLING_PAT:-}" ]; then
y=$(date -u +%Y); m=$(date -u +%-m)
# Public repos' minutes are free and don't use the included 3,000, so leave them out.
public=$(curl -fsS "https://api.github.com/orgs/ericdahl-dev/repos?type=public&per_page=100" \
| python3 -c 'import json,sys; print(" ".join(r["name"] for r in json.load(sys.stdin)))') || public=""
minutes=$(curl -fsS -H "Authorization: Bearer $GH_BILLING_PAT" -H "Accept: application/vnd.github+json" \
"https://api.github.com/organizations/ericdahl-dev/settings/billing/usage?year=$y&month=$m" \
| PUBLIC="$public" python3 -c '
import json, os, sys, collections
public = set(os.environ["PUBLIC"].split())
items = [i for i in json.load(sys.stdin)["usageItems"]
if i["unitType"] == "Minutes" and i["repositoryName"] not in public]
by_repo = collections.Counter(); linux = paid = 0.0
for i in items:
by_repo[i["repositoryName"]] += i["quantity"]
if i["sku"] == "Actions Linux": linux += i["quantity"]
paid += i["netAmount"]
print(f"Private-repo Linux minutes this month: {linux:.0f} of 3,000 included")
print(f"Billed this month: ${paid:.2f} (macOS/Windows and any overage)")
print("Top private repos: " + ", ".join(f"{r} {q:.0f}" for r, q in by_repo.most_common(5)))
' 2>&1) || minutes="(billing API call failed)"
summary=$(printf '%s\n\nGitHub-hosted Actions (ger3 runs are free and not counted)\n%s\n' "$summary" "$minutes")
fi

body=$(printf 'From: ger3 CI <alerts@ericdahl.dev>\r\nTo: %s\r\nSubject: ger3 CI load, week ending %s\r\n\r\n%s\r\n' \
"$REPORT_TO" "$(date -u +%Y-%m-%d)" "$summary")

Expand Down
Loading