Track GitHub Traffic #154
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Track GitHub Traffic | |
| on: | |
| schedule: | |
| - cron: '0 1 * * *' # Daily UTC 1:00 (Beijing 9:00) | |
| workflow_dispatch: | |
| jobs: | |
| track: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Fetch and deduplicate traffic data | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| REPO: ${{ github.repository }} | |
| run: | | |
| mkdir -p traffic | |
| # Fetch 14-day rolling window from GitHub API → temp files | |
| curl -s -H "Authorization: token $GH_TOKEN" \ | |
| "https://api.github.com/repos/$REPO/traffic/clones" > /tmp/clones.json | |
| curl -s -H "Authorization: token $GH_TOKEN" \ | |
| "https://api.github.com/repos/$REPO/traffic/views" > /tmp/views.json | |
| curl -s -H "Authorization: token $GH_TOKEN" \ | |
| "https://api.github.com/repos/$REPO" > /tmp/stats.json | |
| # Extract daily entries, deduplicate by date, append only new days | |
| python3 << 'PYEOF' | |
| import json, os | |
| from datetime import datetime | |
| def merge_daily(api_file, history_file, key): | |
| """Extract daily entries from API, merge with history, deduplicate by date.""" | |
| try: | |
| with open(api_file) as f: | |
| data = json.load(f) | |
| except Exception as e: | |
| print(f" WARN: {key}: {e}") | |
| return | |
| existing = {} | |
| if os.path.isfile(history_file): | |
| with open(history_file) as f: | |
| for line in f: | |
| line = line.strip() | |
| if not line: | |
| continue | |
| try: | |
| entry = json.loads(line) | |
| existing[entry["date"]] = entry | |
| except: | |
| pass | |
| new_count = 0 | |
| for day in data.get(key, []): | |
| date = day["timestamp"][:10] | |
| entry = {"date": date, "count": day["count"], "uniques": day["uniques"]} | |
| if date not in existing or day["count"] > existing[date].get("count", 0): | |
| if date not in existing: | |
| new_count += 1 | |
| existing[date] = entry | |
| sorted_entries = sorted(existing.values(), key=lambda x: x["date"]) | |
| with open(history_file, "w") as f: | |
| for entry in sorted_entries: | |
| f.write(json.dumps(entry) + "\n") | |
| total = sum(e["count"] for e in sorted_entries) | |
| total_uniq = sum(e["uniques"] for e in sorted_entries) | |
| print(f" {key}: {len(sorted_entries)} days ({new_count} new), total={total} uniques={total_uniq}") | |
| merge_daily("/tmp/clones.json", "traffic/clones-history.ndjson", "clones") | |
| merge_daily("/tmp/views.json", "traffic/views-history.ndjson", "views") | |
| # Repo stats snapshot (stars, forks, watchers) | |
| try: | |
| with open("/tmp/stats.json") as f: | |
| s = json.load(f) | |
| entry = { | |
| "date": datetime.utcnow().strftime("%Y-%m-%d"), | |
| "stars": s.get("stargazers_count", 0), | |
| "forks": s.get("forks_count", 0), | |
| "watchers": s.get("subscribers_count", 0), | |
| "open_issues": s.get("open_issues_count", 0), | |
| } | |
| hist = "traffic/stats-history.ndjson" | |
| existing_dates = set() | |
| if os.path.isfile(hist): | |
| with open(hist) as f: | |
| for line in f: | |
| try: | |
| existing_dates.add(json.loads(line.strip())["date"]) | |
| except: | |
| pass | |
| if entry["date"] not in existing_dates: | |
| with open(hist, "a") as f: | |
| f.write(json.dumps(entry) + "\n") | |
| print(f" stats: stars={entry['stars']} forks={entry['forks']}") | |
| else: | |
| print(f" stats: already recorded for {entry['date']}") | |
| except Exception as e: | |
| print(f" WARN: stats: {e}") | |
| PYEOF | |
| - name: Commit traffic data | |
| run: | | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git config user.name "github-actions[bot]" | |
| git add traffic/ | |
| git diff --staged --quiet || git commit -m "chore: traffic data $(date -u +%Y-%m-%d)" | |
| git push |