Skip to content

Desktop Download Badges #3

Desktop Download Badges

Desktop Download Badges #3

# Refreshes the per-platform desktop download counters behind the README badges.
#
# shields.io cannot do this on its own: its asset wildcards silently report 0
# (a tag whose .dmg had 39,877 downloads returns 0 for `*.dmg`), exact asset
# names embed the version so they break on every release, and `dynamic/json`
# rejects every filter expression. So we sum the counts here and publish them
# as shields `endpoint` documents.
#
# The documents land on the orphan `badges` branch, never on `main` — `main` is
# protected and rejects pushes from everyone, CI included.
name: Desktop Download Badges
on:
schedule:
# Once a day is plenty; the counters move slowly and the API is rate-limited.
- cron: '17 4 * * *'
workflow_dispatch: {}
permissions:
contents: write
concurrency:
group: desktop-download-badges
cancel-in-progress: true
jobs:
refresh:
runs-on: ubuntu-latest
steps:
- name: Checkout the badges branch
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # pinned from v4
with:
ref: badges
persist-credentials: true
- name: Sum the .dmg and .exe download counts
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Desktop installers shipped from this repo up to v0.1.0 and move to
# pythinker-desktop-releases from the next release on. Summing both
# keeps the counters continuous across that move.
RELEASES_REPOS: PyModel/pythinker-code PyModel/pythinker-desktop-releases
run: |
set -euo pipefail
# --paginate walks every release, so the totals cover the whole
# history rather than just the latest tag. jq -s concatenates the one
# array each repo produces into a single list of releases.
for repo in ${RELEASES_REPOS}; do
gh api --paginate "repos/${repo}/releases"
done | jq -s 'add' > releases.json
# An empty suffix matches every asset, which is what the combined
# counter wants; `endswith("")` is true for any string.
write_badge() {
local suffix="$1" label="$2" out="$3"
local total
total="$(jq --arg s "$suffix" '
[ .[].assets[]
| select(.name | ascii_downcase | endswith($s))
| .download_count
] | add // 0
' releases.json)"
jq -n --arg label "$label" --arg message "$total" '{
schemaVersion: 1,
label: $label,
message: $message,
color: "4D6BFE"
}' > "$out"
echo "${label}: ${total}"
}
write_badge '.dmg' 'macOS .dmg' desktop-dmg.json
write_badge '.exe' 'Windows .exe' desktop-exe.json
# The shields `github/downloads/.../total` route reads one repository,
# so the combined counter has to be summed here like the other two.
write_badge '' 'desktop' desktop-total.json
rm -f releases.json
- name: Publish if the counts moved
run: |
set -euo pipefail
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
# Stage before comparing: a document added in this run is untracked,
# and `git diff` on an untracked path reports no change at all.
git add desktop-dmg.json desktop-exe.json desktop-total.json
if git diff --cached --quiet; then
echo 'Counts unchanged; nothing to publish.'
exit 0
fi
git commit -m 'chore: refresh desktop download counts'
git push origin badges