Public dashboard showing community activity metrics for Apache projects, with 12-month trend lines for meaningful context.
Status: Working dashboard deployed at https://projects.apache.org/metrics/ — fetches foundation data from projects.apache.org, mailing list stats from Pony Mail Foal API, Git/GitHub activity (with SVN support), new committer dates from Whimsy LDAP, and renders a per-project dashboard with trend lines, releases, community growth, and activity trend classifications.
cd /path/to/comdev-metrics cp config.example.yml config.yml cp .secrets.example .secrets # Edit .secrets with your GitHub token # Edit config.yml as needed # Run with uv (no install needed) uv run asfmetrics # Single project uv run asfmetrics --project comdev # Skip mailing lists (just fetch foundation + git data) uv run asfmetrics --skip-mailing-lists # Skip git/VCS collection uv run asfmetrics --skip-git # Force re-fetch everything (bypass cache) uv run asfmetrics --force-refresh # Re-fetch the GitHub repo inventory uv run asfmetrics --refresh-repos # View results cd site && python3 -m http.server 8888 # Open http://localhost:8888
# Install dev dependencies (includes pytest) uv sync --all-groups # Run all tests uv run pytest -v
createTimestamp, cross-referenced with project group membershippreferences.jsonsite/data/)Only lists with actual traffic in the 12-month window are shown.
Data is aggressively cached to minimize API calls:
site/data/_cache/mailing_lists/<project>.jsonsite/data/_cache/git/<project>.json--force-refresh to clear all caches and re-fetch everything.On a typical weekly run mid-month, the mailing list phase completes in seconds (cache hits from prior runs) instead of making hundreds of API calls.
See config.example.yml. Config is searched in order:
./config.yml~/.asfmetrics/config.yml/etc/asfmetrics/config.ymlGitHub token (needed for git activity collection; optional but strongly recommended):
GITHUB_TOKEN environment variable.secrets file in the project directory (line: GITHUB_TOKEN=ghp_...)~/.secrets file (user-level fallback)config.yml data_sources.git.token fieldCopy .secrets.example → .secrets and fill in your token. The .secrets file is in .gitignore and will never be committed.
Most projects use GitHub. For projects still on Subversion, add an override in config.yml:
project_overrides: httpd: vcs: svn svn_path: https://svn.apache.org/repos/asf/httpd/httpd/trunk
SVN-only projects can also be auto-detected from repositories.json — if a project has SVN repos but no GitHub repos, the collector automatically uses svn log.
See config.example.yml for full documentation of override options.
comdev-metrics/ ├── .secrets.example # Template for secrets (GitHub token) ├── config.example.yml # Example configuration ├── pyproject.toml # uv/hatch project definition ├── src/asfmetrics/ │ ├── __init__.py # Package version │ ├── cli.py # Entry point — orchestrates all phases │ ├── config.py # Config loading (YAML, multi-path lookup) │ ├── trends.py # Deterministic activity trend classification │ ├── collectors/ │ │ ├── cache.py # Shared caching utilities (load/save/invalidate) │ │ ├── mailing_lists.py # Pony Mail Foal API + caching │ │ ├── git_activity.py # GitHub API + SVN log collector + caching │ │ ├── github_repos.py # Repo inventory + project classification │ │ └── projects_apache_org.py # Foundation JSON + Whimsy LDAP + roster differ │ ├── analysis/ # Trend calculations (placeholder) │ └── output/ │ └── json_api.py # JSON data writer ├── site/ │ ├── index.html # Overview dashboard (tabs: All Projects, Growth, Releases, Mailing Lists, Activity Trends) │ ├── project.html # Per-project detail page (?id=projectname) │ ├── about.html # Data sources and methodology documentation │ └── data/ # Generated JSON + cache (git-ignored) │ ├── _cache/ │ │ ├── doap-warnings.json │ │ ├── mailing_lists/ # Per-project mailing list cache │ │ ├── git/ # Per-project git activity cache │ │ ├── committees.json │ │ ├── releases.json │ │ ├── new_committers.json │ │ ├── mailing_summary.json │ │ └── activity_trends.json │ ├── _state/ # Roster diff state between runs │ ├── _project_map.json # GitHub repo → project classification │ ├── <project>.json # Mailing list data │ └── <project>_git.json # Git activity data ├── DATA_SOURCES.md # Where all the data comes from ├── PLAN.md # Execution plan and milestones ├── tests/ # Unit tests (pytest) └── LICENSE # Apache License 2.0
usage: asfmetrics [-h] [--config CONFIG] [--project PROJECT]
[--skip-mailing-lists] [--skip-git]
[--force-refresh] [--refresh-repos]
Options:
--config CONFIG Path to config.yml (default: auto-discover)
--project PROJECT Run for a single project only
--skip-mailing-lists Skip mailing list collection
--skip-git Skip git/VCS activity collection
--force-refresh Clear all caches and re-fetch everything
--refresh-repos Re-fetch the GitHub repo inventory (project → repos map)
The CLI runs these phases in order:
_project_map.json (only when needed: first run, --refresh-repos, or --force-refresh)--skip-mailing-lists) + summary file--skip-git)activity_trends.jsonFive tabs:
Explains all data sources, methodology, what's measured, and limitations.
Production:
The code and data are installed on the projects.apache.org host, at /var/www/metrics with output at https://projects.apache.org/metrics.
The build.sh script is run as a daily cron job:
Sundays, 19:45 ./build.sh weekly >>/var/log/www-data/metrics_$(date “+%Y-%m”).log
Other days, 19:40 ./build.sh daily >>/var/log/www-data/metrics_$(date “+%Y-%m”).log
Local testing:
https://apache.github.io/comdev-metrics/ — built and deployed via GitHub Actions.
The GitHub Actions workflow (.github/workflows/metrics.yml):
config.example.yml → config.ymluv run asfmetrics)site/ directory as a Pages artifact (14-day retention)No files in the repository are modified by the build — only the Pages artifact is updated. The GitHub Actions-provided GITHUB_TOKEN handles API authentication automatically (ASF has GitHub Enterprise rate limits).
Currently triggered manually (workflow_dispatch); scheduled runs TBD.
There is another workflow (.github/workflows/updatecode.yml) which can be manually triggered to regenerate the site without downloading any Git or mail data.
For local testing:
cp config.example.yml config.yml cp .secrets.example .secrets # add your GitHub token uv run asfmetrics --project comdev uv run pytest -v # run tests
Apache License 2.0