diff --git a/.github/workflows/clone-stats.yml b/.github/workflows/clone-stats.yml index 2918e2ff..ea397bc4 100644 --- a/.github/workflows/clone-stats.yml +++ b/.github/workflows/clone-stats.yml @@ -24,14 +24,45 @@ jobs: - name: Switch to stats branch run: git checkout -B stats + - name: Restore existing stats history + run: | + if git show origin/stats:stats/clone_history.json >/tmp/clone_history.json 2>/dev/null; then + mkdir -p stats + cp /tmp/clone_history.json stats/clone_history.json + fi + - name: Fetch clone stats from GitHub API run: | - TOKEN="${TRAFFIC_TOKEN:-${{ github.token }}}" - curl -fsSL \ - -H "Authorization: Bearer ${TOKEN}" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/${{ github.repository }}/traffic/clones" \ - -o traffic.json + API_URL="https://api.github.com/repos/${{ github.repository }}/traffic/clones" + + fetch_traffic() { + local token="$1" + local code + code=$(curl -sS -L \ + -H "Authorization: Bearer ${token}" \ + -H "Accept: application/vnd.github+json" \ + -o traffic.json \ + -w "%{http_code}" \ + "${API_URL}") + echo "${code}" + } + + if [ -n "${TRAFFIC_TOKEN}" ]; then + STATUS=$(fetch_traffic "${TRAFFIC_TOKEN}") + + if [ "${STATUS}" = "401" ] || [ "${STATUS}" = "403" ]; then + echo "TRAFFIC_TOKEN was rejected (${STATUS}); retrying with github.token fallback." + STATUS=$(fetch_traffic "${{ github.token }}") + fi + else + STATUS=$(fetch_traffic "${{ github.token }}") + fi + + if [ "${STATUS}" -lt 200 ] || [ "${STATUS}" -ge 300 ]; then + echo "Failed to fetch clone traffic (HTTP ${STATUS}). Response:" + cat traffic.json + exit 1 + fi # Fail early with a clear message if GitHub API did not return usable traffic data. if [ "$(jq -r 'has("count") and has("uniques")' traffic.json)" != "true" ]; then @@ -44,13 +75,29 @@ jobs: run: | COUNT=$(jq '.count' traffic.json) UNIQUES=$(jq '.uniques' traffic.json) + + if [ -f stats/clone_history.json ]; then + jq -s ' + (.[0] + .[1]) + | sort_by(.timestamp) + | group_by(.timestamp) + | map(max_by(.count)) + ' stats/clone_history.json <(jq '.clones' traffic.json) > stats/clone_history_merged.json + else + jq '.clones' traffic.json > stats/clone_history_merged.json + fi + + mv stats/clone_history_merged.json stats/clone_history.json + TOTAL_COUNT=$(jq '[.[].count] | add // 0' stats/clone_history.json) + mkdir -p stats - echo "{ \"count\": $COUNT, \"uniques\": $UNIQUES }" > stats/clones.json + echo "{ \"count\": $COUNT, \"uniques\": $UNIQUES, \"total_count\": $TOTAL_COUNT }" > stats/clones.json - name: Commit and push to stats branch run: | git config --global user.name "github-actions" git config --global user.email "actions@github.com" + git add stats/clone_history.json git add stats/clones.json git commit -m "Update clone stats" || exit 0 git push origin stats --force diff --git a/README.md b/README.md index 2406b6dc..f032fe0c 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@

Centralize. Unify. Govern.

-![Clones (14d total)](https://img.shields.io/badge/dynamic/json?color=blue&label=Clones%20(14d%20total)&query=count&url=https://raw.githubusercontent.com/Sendipad/uph/stats/clones.json) +![Clones (all-time)](https://img.shields.io/badge/dynamic/json?color=blue&label=Clones%20(all-time)&query=total_count&url=https://raw.githubusercontent.com/Sendipad/uph/stats/clones.json) ![Unique cloners (14d)](https://img.shields.io/badge/dynamic/json?color=informational&label=Unique%20cloners%20(14d)&query=uniques&url=https://raw.githubusercontent.com/Sendipad/uph/stats/clones.json) [![CI develop](https://img.shields.io/github/actions/workflow/status/Sendipad/uph/ci.yml?branch=develop&job=test_v17&label=CI%20develop)](https://github.com/Sendipad/uph/actions/workflows/ci.yml) [![CI v16](https://img.shields.io/github/actions/workflow/status/Sendipad/uph/ci.yml?branch=develop&job=test_v16&label=CI%20v16)](https://github.com/Sendipad/uph/actions/workflows/ci.yml) diff --git a/stats/README.md b/stats/README.md index ec07391b..9d755809 100644 --- a/stats/README.md +++ b/stats/README.md @@ -8,4 +8,5 @@ This folder is used by the clone-stats GitHub Action. If you do not see recent data, trigger the **Update Clone Stats** workflow manually and wait for cache refresh. - If clone totals stay empty, add a `TRAFFIC_TOKEN` repository secret (classic PAT with `repo` scope) so the workflow can access the traffic API reliably. -- `stats/clones.json` now stores both `count` (total clones in last 14 days) and `uniques` (unique cloners in last 14 days). +- `stats/clones.json` stores `count` (total clones in last 14 days), `uniques` (unique cloners in last 14 days), and `total_count` (cumulative clones tracked over time). +- `stats/clone_history.json` stores daily clone snapshots so cumulative totals survive the 14-day API window.