From 990e0dd1eb94e6420a554f6a11d849b6bc70e216 Mon Sep 17 00:00:00 2001 From: Stefano Date: Tue, 7 Oct 2025 00:02:05 -0500 Subject: [PATCH 1/6] Added metrics workflows (tested in separate repo) --- .github/workflows/clone-metrics.yml | 72 +++++++++++++++++++++++++++++ .github/workflows/view-metrics.yml | 72 +++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 .github/workflows/clone-metrics.yml create mode 100644 .github/workflows/view-metrics.yml diff --git a/.github/workflows/clone-metrics.yml b/.github/workflows/clone-metrics.yml new file mode 100644 index 0000000..181f81c --- /dev/null +++ b/.github/workflows/clone-metrics.yml @@ -0,0 +1,72 @@ +name: Track Clone Metrics via GitHub App + +on: + schedule: + - cron: "30 4 * * *" # Daily at 04:00 UTC + workflow_dispatch: + +jobs: + track-clone-metrics: + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Authenticate as GitHub App + id: generate_token + uses: tibdex/github-app-token@v2.1.0 + with: + app_id: ${{ secrets.APP_ID }} + private_key: ${{ secrets.APP_PRIVATE_KEY }} + + - name: Retrieve clone data + env: + TOKEN: ${{ steps.generate_token.outputs.token }} + run: | + mkdir -p .metrics + echo "Fetching clone data for ${{ github.repository }}..." + curl -s -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/traffic/clones?per=day" \ + > .metrics/clones.json + jq '. | {total_14d: .count, unique_14d: .uniques, days: (.clones|length)}' .metrics/clones.json + + - name: Update unified clone metrics CSV + run: | + mkdir -p .metrics + CSV=".metrics/clone_metrics.csv" + + TOTAL=$(jq '.count' .metrics/clones.json) + UNIQUE_TOTAL=$(jq '.uniques' .metrics/clones.json) + + if [ ! -f "$CSV" ]; then + echo "date,clones,unique_cloners,total_clones_14d,unique_cloners_14d" > "$CSV" + fi + + jq -r --arg total "$TOTAL" --arg uniques "$UNIQUE_TOTAL" \ + '.clones[] | "\(.timestamp[0:10]),\(.count),\(.uniques),\($total),\($uniques)"' \ + .metrics/clones.json \ + | while IFS= read -r line; do + date=$(echo "$line" | cut -d',' -f1) + if ! grep -q "^$date," "$CSV"; then + echo "$line" >> "$CSV" + fi + done + + echo "Updated metrics summary:" + tail -n 5 "$CSV" + + - name: Commit and push results + env: + TOKEN: ${{ steps.generate_token.outputs.token }} + run: | + git config user.name "CloneMetrics[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + git add .metrics/clone_metrics.csv + git commit -m "Automated update: repository clone metrics" || echo "No new data to commit." + git pull --rebase origin develop || true + git push https://x-access-token:${TOKEN}@github.com/${{ github.repository }} HEAD diff --git a/.github/workflows/view-metrics.yml b/.github/workflows/view-metrics.yml new file mode 100644 index 0000000..9538789 --- /dev/null +++ b/.github/workflows/view-metrics.yml @@ -0,0 +1,72 @@ +name: Track View Metrics via GitHub App + +on: + schedule: + - cron: "30 4 * * *" # Daily at 04:00 UTC + workflow_dispatch: + +jobs: + track-view-metrics: + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Authenticate as GitHub App + id: generate_token + uses: tibdex/github-app-token@v2.1.0 + with: + app_id: ${{ secrets.APP_ID }} + private_key: ${{ secrets.APP_PRIVATE_KEY }} + + - name: Retrieve view data + env: + TOKEN: ${{ steps.generate_token.outputs.token }} + run: | + mkdir -p .metrics + echo "Fetching view data for ${{ github.repository }}..." + curl -s -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/traffic/views?per=day" \ + > .metrics/views.json + jq '. | {total_14d: .count, unique_14d: .uniques, days: (.views|length)}' .metrics/views.json + + - name: Update unified view metrics CSV + run: | + mkdir -p .metrics + CSV=".metrics/view_metrics.csv" + + TOTAL=$(jq '.count' .metrics/views.json) + UNIQUE_TOTAL=$(jq '.uniques' .metrics/views.json) + + if [ ! -f "$CSV" ]; then + echo "date,views,unique_viewers,total_views_14d,unique_viewers_14d" > "$CSV" + fi + + jq -r --arg total "$TOTAL" --arg uniques "$UNIQUE_TOTAL" \ + '.views[] | "\(.timestamp[0:10]),\(.count),\(.uniques),\($total),\($uniques)"' \ + .metrics/views.json \ + | while IFS= read -r line; do + date=$(echo "$line" | cut -d',' -f1) + if ! grep -q "^$date," "$CSV"; then + echo "$line" >> "$CSV" + fi + done + + echo "Updated metrics summary:" + tail -n 5 "$CSV" + + - name: Commit and push results + env: + TOKEN: ${{ steps.generate_token.outputs.token }} + run: | + git config user.name "ViewMetrics[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + git add .metrics/view_metrics.csv + git commit -m "Automated update: repository view metrics" || echo "No new data to commit." + git pull --rebase origin develop || true + git push https://x-access-token:${TOKEN}@github.com/${{ github.repository }} HEAD From 1b87ec897d877bf4db8e3fc7a86549e43941e650 Mon Sep 17 00:00:00 2001 From: Stefano Date: Tue, 7 Oct 2025 00:02:56 -0500 Subject: [PATCH 2/6] Removed non-working workflows --- .github/workflows/clone-trend.yml | 63 -------------- .github/workflows/traffic-trend.yml | 127 ---------------------------- 2 files changed, 190 deletions(-) delete mode 100644 .github/workflows/clone-trend.yml delete mode 100644 .github/workflows/traffic-trend.yml diff --git a/.github/workflows/clone-trend.yml b/.github/workflows/clone-trend.yml deleted file mode 100644 index b398401..0000000 --- a/.github/workflows/clone-trend.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Track clone stats -on: - schedule: [{ cron: "7 3 * * *" }] # daily at 03:07 UTC - workflow_dispatch: -permissions: - contents: write - actions: read - id-token: write -jobs: - track: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Install jq - run: sudo apt-get update && sudo apt-get install -y jq - - - name: Fetch last 14 days of clone data - env: - REPO: ${{ github.repository }} # owner/repo - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - curl -s -H "Authorization: Bearer $GH_TOKEN" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/$REPO/traffic/clones?per=day" > clones.json - cat clones.json | jq '.' - - - name: Ensure data directory and CSV - run: | - mkdir -p analytics - if [ ! -f analytics/clone_history.csv ]; then - echo "date,clones,unique_cloners" > analytics/clone_history.csv - fi - - - name: Merge new data into CSV (de-duplicate by date) - run: | - # Build a temp map of existing dates to avoid duplicates - awk -F, 'NR>1 {print $1}' analytics/clone_history.csv | sort > existing_dates.txt - - # Append any missing dates from API response - jq -r '.clones[] | "\(.timestamp[0:10]),\(.count),\(.uniques)"' clones.json \ - | while IFS= read -r line; do - d=$(echo "$line" | cut -d',' -f1) - if ! grep -qx "$d" existing_dates.txt; then - echo "$line" >> analytics/clone_history.csv - fi - done - - # Sort CSV by date (header stays on top) - { head -n1 analytics/clone_history.csv && tail -n +2 analytics/clone_history.csv | sort; } > analytics/clone_history.sorted.csv - mv analytics/clone_history.sorted.csv analytics/clone_history.csv - - - name: Commit changes - run: | - if git diff --quiet; then - echo "No changes." - else - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add analytics/clone_history.csv - git commit -m "Update clone history" - git push - fi diff --git a/.github/workflows/traffic-trend.yml b/.github/workflows/traffic-trend.yml deleted file mode 100644 index 1c13725..0000000 --- a/.github/workflows/traffic-trend.yml +++ /dev/null @@ -1,127 +0,0 @@ -name: Track clones & downloads -on: - schedule: [{ cron: "12 9 * * *" }] # daily 09:12 UTC (~04:12 America/Chicago) - workflow_dispatch: - -permissions: - contents: write - actions: read - id-token: write - -jobs: - track: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Install jq - run: sudo apt-get update && sudo apt-get install -y jq - - # ---------- CLONE STATS (14-day window, accumulated to CSV) ---------- - - name: Fetch last 14 days of clone data - env: - REPO: ${{ github.repository }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - curl -s -H "Authorization: Bearer $GH_TOKEN" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/$REPO/traffic/clones?per=day" > clones.json - - - name: Merge clones into CSV - run: | - mkdir -p analytics - CSV="analytics/clone_history.csv" - [ -f "$CSV" ] || echo "date,clones,unique_cloners" > "$CSV" - - # existing dates to avoid dupes - awk -F, 'NR>1 {print $1}' "$CSV" | sort -u > .existing_clone_dates.txt || true - - jq -r '.clones[] | "\(.timestamp[0:10]),\(.count),\(.uniques)"' clones.json \ - | while IFS= read -r line; do - d="${line%%,*}" - if ! grep -qx "$d" .existing_clone_dates.txt; then - echo "$line" >> "$CSV" - fi - done - - # sort by date (keep header) - { head -n1 "$CSV"; tail -n +2 "$CSV" | sort; } > "$CSV.sorted" - mv "$CSV.sorted" "$CSV" - - # ---------- RELEASE DOWNLOADS (cumulative snapshot per day) ---------- - - name: Fetch all releases (paginate) - env: - REPO: ${{ github.repository }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - set -e - tmpdir=$(mktemp -d) - page=1 - > "$tmpdir/all.json" - while :; do - resp=$(curl -s -H "Authorization: Bearer $GH_TOKEN" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/$REPO/releases?per_page=100&page=$page") - count=$(echo "$resp" | jq 'length') - if [ "$count" -eq 0 ]; then break; fi - echo "$resp" | jq '.[]' >> "$tmpdir/all.json" - page=$((page+1)) - done - - # Wrap into an array if we added anything - if [ -s "$tmpdir/all.json" ]; then - echo "[" > releases.json - # join with commas - sed -e '$!s/$/,/' "$tmpdir/all.json" >> releases.json - echo "]" >> releases.json - else - echo "[]" > releases.json - fi - - - name: Merge downloads into CSVs - run: | - mkdir -p analytics - SNAPCSV="analytics/downloads_snapshot.csv" - TOTCSV="analytics/downloads_totals.csv" - today=$(date -u +%F) - - # Create CSVs if missing - [ -f "$SNAPCSV" ] || echo "date,release_tag,asset_id,asset_name,download_count" > "$SNAPCSV" - [ -f "$TOTCSV" ] || echo "date,total_downloads" > "$TOTCSV" - - # Avoid duplicating today's snapshot rows - # (filter if today's rows already recorded) - if grep -q "^$today," "$SNAPCSV"; then - echo "Download snapshot for $today already exists; skipping append." - else - # Snapshot rows: one per asset - jq -r ' - .[] - | select(.draft==false) - | .tag_name as $tag - | (.assets // []) - | .[] - | [$tag, .id, .name, (.download_count // 0)] - | @csv - ' releases.json \ - | sed 's/^/'"$today"',/' >> "$SNAPCSV" - fi - - # Totals row: sum all asset download_count across all releases - if ! grep -q "^$today," "$TOTCSV"; then - total=$(jq '[ .[] | select(.draft==false) | (.assets // []) | .[] | (.download_count // 0) ] | add // 0' releases.json) - echo "$today,$total" >> "$TOTCSV" - fi - - # ---------- COMMIT ---------- - - name: Commit changes - run: | - if git diff --quiet; then - echo "No changes." - else - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add analytics/clone_history.csv analytics/downloads_snapshot.csv analytics/downloads_totals.csv - git commit -m "Update clone & download history" - git push - fi From 1692c012b2acd51cf2a5ec965171fd9c285ef4c7 Mon Sep 17 00:00:00 2001 From: Stefano Date: Tue, 7 Oct 2025 00:36:56 -0500 Subject: [PATCH 3/6] Added download-metrics.yml + commit/push to metrics branch --- .github/workflows/clone-metrics.yml | 7 ++- .github/workflows/download-metrics.yml | 84 ++++++++++++++++++++++++++ .github/workflows/view-metrics.yml | 7 ++- 3 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/download-metrics.yml diff --git a/.github/workflows/clone-metrics.yml b/.github/workflows/clone-metrics.yml index 181f81c..e66dd1a 100644 --- a/.github/workflows/clone-metrics.yml +++ b/.github/workflows/clone-metrics.yml @@ -2,7 +2,7 @@ name: Track Clone Metrics via GitHub App on: schedule: - - cron: "30 4 * * *" # Daily at 04:00 UTC + - cron: "30 4 * * *" # Every day at 4:30 AM UTC workflow_dispatch: jobs: @@ -14,6 +14,9 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + ref: metrics + fetch-depth: 0 - name: Authenticate as GitHub App id: generate_token @@ -68,5 +71,5 @@ jobs: git add .metrics/clone_metrics.csv git commit -m "Automated update: repository clone metrics" || echo "No new data to commit." - git pull --rebase origin develop || true + git pull --rebase origin metrics || true git push https://x-access-token:${TOKEN}@github.com/${{ github.repository }} HEAD diff --git a/.github/workflows/download-metrics.yml b/.github/workflows/download-metrics.yml new file mode 100644 index 0000000..fad8bb1 --- /dev/null +++ b/.github/workflows/download-metrics.yml @@ -0,0 +1,84 @@ +name: Track Download Metrics via GitHub App + +on: + schedule: + - cron: "30 4 * * *" # Every day at 4:30 AM UTC + workflow_dispatch: + +jobs: + track-download-metrics: + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: metrics + fetch-depth: 0 + + - name: Authenticate as GitHub App + id: generate_token + uses: tibdex/github-app-token@v2.1.0 + with: + app_id: ${{ secrets.APP_ID }} + private_key: ${{ secrets.APP_PRIVATE_KEY }} + + - name: Retrieve download data + env: + TOKEN: ${{ steps.generate_token.outputs.token }} + run: | + mkdir -p .metrics + echo "Fetching download data for ${{ github.repository }}..." + + # Fetch all pages of releases + curl -s -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/releases?per_page=100" \ + > .metrics/releases.json + + echo "Raw releases data (first 3 releases):" + jq '.[0:3] | .[] | {tag_name, assets_count: (.assets | length), assets: [.assets[] | {name: .name, download_count: .download_count}]}' .metrics/releases.json + + # Extract download counts from releases + jq '[.[] | {tag_name: .tag_name, published_at: .published_at, assets: [.assets[] | {name: .name, download_count: .download_count}]}]' .metrics/releases.json > .metrics/downloads.json + + echo "Download data summary:" + jq '[.[] | {tag: .tag_name, date: .published_at, total_downloads: ([.assets[].download_count] | add), assets_count: (.assets | length)}]' .metrics/downloads.json + + - name: Update unified download metrics CSV + run: | + mkdir -p .metrics + CSV=".metrics/download_metrics.csv" + + if [ ! -f "$CSV" ]; then + echo "date,release_tag,asset_name,downloads,total_release_downloads" > "$CSV" + fi + + jq -r '.[] | + if (.assets | length > 0) then + .assets[] as $asset | + "\(.published_at[0:10]),\(.tag_name),\($asset.name),\($asset.download_count),\([.assets[].download_count] | add)" + else + "\(.published_at[0:10]),\(.tag_name),,0,0" + end' \ + .metrics/downloads.json \ + | while IFS= read -r line; do + echo "$line" >> "$CSV" + done + + echo "Updated metrics summary:" + tail -n 5 "$CSV" + + - name: Commit and push results + env: + TOKEN: ${{ steps.generate_token.outputs.token }} + run: | + git config user.name "DownloadMetrics[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + git add .metrics/download_metrics.csv + git commit -m "Automated update: repository download metrics" || echo "No new data to commit." + git pull --rebase origin metrics || true + git push https://x-access-token:${TOKEN}@github.com/${{ github.repository }} HEAD diff --git a/.github/workflows/view-metrics.yml b/.github/workflows/view-metrics.yml index 9538789..97e7f36 100644 --- a/.github/workflows/view-metrics.yml +++ b/.github/workflows/view-metrics.yml @@ -2,7 +2,7 @@ name: Track View Metrics via GitHub App on: schedule: - - cron: "30 4 * * *" # Daily at 04:00 UTC + - cron: "0 */2 * * *" # Every 2 hours workflow_dispatch: jobs: @@ -14,6 +14,9 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + ref: metrics + fetch-depth: 0 - name: Authenticate as GitHub App id: generate_token @@ -68,5 +71,5 @@ jobs: git add .metrics/view_metrics.csv git commit -m "Automated update: repository view metrics" || echo "No new data to commit." - git pull --rebase origin develop || true + git pull --rebase origin metrics || true git push https://x-access-token:${TOKEN}@github.com/${{ github.repository }} HEAD From 1f6e53d7258c0fc4e1e1a83e56fc1b4f3817ac20 Mon Sep 17 00:00:00 2001 From: Stefano Date: Tue, 7 Oct 2025 09:43:52 -0500 Subject: [PATCH 4/6] Minor fix to download-metrics.yml --- .github/workflows/download-metrics.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/download-metrics.yml b/.github/workflows/download-metrics.yml index fad8bb1..e55a2a1 100644 --- a/.github/workflows/download-metrics.yml +++ b/.github/workflows/download-metrics.yml @@ -63,10 +63,7 @@ jobs: else "\(.published_at[0:10]),\(.tag_name),,0,0" end' \ - .metrics/downloads.json \ - | while IFS= read -r line; do - echo "$line" >> "$CSV" - done + .metrics/downloads.json >> "$CSV" echo "Updated metrics summary:" tail -n 5 "$CSV" From 50f058592c64a4cba530bc388192babdd1a306df Mon Sep 17 00:00:00 2001 From: Stefano Date: Tue, 7 Oct 2025 09:47:37 -0500 Subject: [PATCH 5/6] Minor fix to download-metrics.yml --- .github/workflows/download-metrics.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/download-metrics.yml b/.github/workflows/download-metrics.yml index e55a2a1..6af1d32 100644 --- a/.github/workflows/download-metrics.yml +++ b/.github/workflows/download-metrics.yml @@ -53,16 +53,10 @@ jobs: CSV=".metrics/download_metrics.csv" if [ ! -f "$CSV" ]; then - echo "date,release_tag,asset_name,downloads,total_release_downloads" > "$CSV" + echo "date,release_tag,total_downloads" > "$CSV" fi - jq -r '.[] | - if (.assets | length > 0) then - .assets[] as $asset | - "\(.published_at[0:10]),\(.tag_name),\($asset.name),\($asset.download_count),\([.assets[].download_count] | add)" - else - "\(.published_at[0:10]),\(.tag_name),,0,0" - end' \ + jq -r '.[] | "\(.published_at[0:10]),\(.tag_name),\([.assets[].download_count] | add)"' \ .metrics/downloads.json >> "$CSV" echo "Updated metrics summary:" From 3c609636d55cd625a8095be7c67bcb90e2c27370 Mon Sep 17 00:00:00 2001 From: Stefano Date: Tue, 7 Oct 2025 10:06:55 -0500 Subject: [PATCH 6/6] Download-metrics.yml rewrites the file entirely --- .github/workflows/download-metrics.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/download-metrics.yml b/.github/workflows/download-metrics.yml index 6af1d32..873fa6e 100644 --- a/.github/workflows/download-metrics.yml +++ b/.github/workflows/download-metrics.yml @@ -52,12 +52,9 @@ jobs: mkdir -p .metrics CSV=".metrics/download_metrics.csv" - if [ ! -f "$CSV" ]; then - echo "date,release_tag,total_downloads" > "$CSV" - fi - - jq -r '.[] | "\(.published_at[0:10]),\(.tag_name),\([.assets[].download_count] | add)"' \ - .metrics/downloads.json >> "$CSV" + (echo "date,release_tag,total_downloads"; \ + jq -r '.[] | "\(.published_at[0:10]),\(.tag_name),\([.assets[].download_count] | add)"' \ + .metrics/downloads.json) > "$CSV" echo "Updated metrics summary:" tail -n 5 "$CSV"