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
92 changes: 92 additions & 0 deletions .github/workflows/package-stats.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: Package stats

# Regenerate GHCR package download-statistics charts for DPM installs.
# Scrapes the public Packages page (no read:packages token required).
# Separate from release-stats.yml — never writes release-downloads-* files.
#
# Generated files are published to the `release-stats-data` branch (not
# `main`) under the package-downloads-* prefix. The README embeds them via
# raw.githubusercontent.com URLs because the `main` branch ruleset requires
# all changes to go through a pull request and this bot commit can't satisfy
# that.

on:
workflow_dispatch:
schedule:
# Daily at 06:47 UTC (offset from release-stats at 06:17).
- cron: "47 6 * * *"

permissions:
contents: write

concurrency:
group: package-stats
cancel-in-progress: false

jobs:
regenerate:
name: Regenerate package download-stats charts
runs-on: self-hosted
timeout-minutes: 10
steps:
- name: Check out repository
# actions/checkout@v7.0.0
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0

- name: Seed history from release-stats-data branch
run: |
set -euo pipefail
history_file="docs/assets/package-downloads-history.jsonl"
mkdir -p docs/assets
if git fetch origin release-stats-data:refs/remotes/origin/release-stats-data 2>/dev/null; then
git show origin/release-stats-data:"${history_file}" > "${history_file}" 2>/dev/null || true
fi

- name: Generate charts + append daily snapshot
run: bash scripts/package-stats.sh

- name: Publish package-downloads-* to release-stats-data branch
run: |
set -euo pipefail
files=(
docs/assets/package-downloads-monthly.svg
docs/assets/package-downloads.md
docs/assets/package-downloads-history.jsonl
)

# Stash generated files before switching branches —
# release-stats-data's tree is unrelated to main's.
tmp="$(mktemp -d)"
for f in "${files[@]}"; do
mkdir -p "${tmp}/$(dirname "${f}")"
cp "${f}" "${tmp}/${f}"
done
for f in "${files[@]}"; do
if git ls-files --error-unmatch "${f}" >/dev/null 2>&1; then
git checkout -- "${f}"
else
rm -f "${f}"
fi
done

if git fetch origin release-stats-data:refs/remotes/origin/release-stats-data; then
git checkout -B release-stats-data refs/remotes/origin/release-stats-data
else
git checkout --orphan release-stats-data
git reset --hard
fi

for f in "${files[@]}"; do
mkdir -p "$(dirname "${f}")"
cp "${tmp}/${f}" "${f}"
done

git add "${files[@]}"
if git diff --cached --quiet; then
echo "Package stats already up to date."
exit 0
fi
git -c user.name="github-actions[bot]" \
-c user.email="github-actions[bot]@users.noreply.github.com" \
commit -m "chore: refresh package download stats"
git push origin release-stats-data
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,27 @@ For general Canton and Daml questions, use the

## Download statistics

(Standalone install downloads only, DPM installs via `dpm install` are not included.)
### Standalone installs

Release asset downloads only (Homebrew formula tarballs and direct GitHub
Release downloads). DPM installs via `dpm install` are counted separately
below. Charts refresh daily via
[`release-stats.yml`](.github/workflows/release-stats.yml). Exact numbers:
[release-downloads.md](https://github.com/bitdynamics-ab/canton-devkit/blob/release-stats-data/docs/assets/release-downloads.md).

![Monthly release downloads](https://raw.githubusercontent.com/bitdynamics-ab/canton-devkit/release-stats-data/docs/assets/release-downloads-monthly.svg)

![All-time downloads per platform](https://raw.githubusercontent.com/bitdynamics-ab/canton-devkit/release-stats-data/docs/assets/release-downloads-by-platform.svg)

### DPM package downloads

GHCR package pulls for `canton-devkit` (the `dpm install` path). Tracked
separately from standalone release downloads. Charts refresh daily via
[`package-stats.yml`](.github/workflows/package-stats.yml). Exact numbers:
[package-downloads.md](https://github.com/bitdynamics-ab/canton-devkit/blob/release-stats-data/docs/assets/package-downloads.md).

![Monthly DPM package downloads](https://raw.githubusercontent.com/bitdynamics-ab/canton-devkit/release-stats-data/docs/assets/package-downloads-monthly.svg)

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for the build, test, and lint
Expand Down
37 changes: 37 additions & 0 deletions scripts/package-stats-monthly.jq
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Monthly download counts from cumulative daily snapshots.
#
# Input: JSON array of { date, total, ... } (use jq -s on a JSONL history file).
# Output: [ { month: "YYYY-MM", downloads: N }, ... ] oldest first.
# Missing calendar months between the first and last observed delta month are filled with 0.
# The first snapshot is baseline only and contributes no delta. Negative steps clamp to 0.

def year_month:
.[0:7];

def month_index:
((.[0:4] | tonumber) * 12) + (.[5:7] | tonumber);

def from_month_index:
((. - 1) / 12 | floor) as $y
| ((. - 1) % 12 + 1) as $m
| ($m | tostring | if length == 1 then "0\(.)" else . end) as $mm
| "\($y)-\($mm)";

sort_by(.date)
| . as $rows
| [ range(1; length)
| { month: ($rows[.].date | year_month),
idx: ($rows[.].date | year_month | month_index),
delta: ([($rows[.].total - $rows[.-1].total), 0] | max) } ]
| group_by(.month)
| map({ month: .[0].month, idx: .[0].idx, downloads: (map(.delta) | add) })
| . as $observed
| if ($observed | length) == 0 then []
else
($observed | map(.idx) | min) as $first
| ($observed | map(.idx) | max) as $last
| ($observed | map({(.month): .downloads}) | add) as $by_month
| [ range($first; $last + 1)
| from_month_index as $m
| { month: $m, downloads: ($by_month[$m] // 0) } ]
end
Loading