feat: smart commit for community-stats - only commit when data changes
- Add generate_shields_endpoints() for dynamic badges - Update workflow to check for significant changes before commit - Support uploading badge JSON to GitHub Gist - Reduce unnecessary commits from hourly to only when data changes
This commit is contained in:
48
.github/workflows/community-stats.yml
vendored
48
.github/workflows/community-stats.yml
vendored
@@ -1,5 +1,5 @@
|
||||
# OpenWebUI 社区统计报告自动生成
|
||||
# 每小时自动获取并更新社区统计数据
|
||||
# 使用 GitHub Gist 存储动态徽章数据,避免频繁 commit
|
||||
|
||||
name: Community Stats
|
||||
|
||||
@@ -39,10 +39,52 @@ jobs:
|
||||
run: |
|
||||
python scripts/openwebui_stats.py
|
||||
|
||||
- name: Check for changes
|
||||
- name: Upload badges to Gist
|
||||
if: ${{ secrets.GIST_TOKEN != '' && secrets.GIST_ID != '' }}
|
||||
env:
|
||||
GIST_TOKEN: ${{ secrets.GIST_TOKEN }}
|
||||
GIST_ID: ${{ secrets.GIST_ID }}
|
||||
run: |
|
||||
# Upload each badge JSON to Gist
|
||||
for badge in docs/badges/*.json; do
|
||||
filename=$(basename "$badge")
|
||||
content=$(cat "$badge" | jq -c '.')
|
||||
|
||||
# Update Gist file
|
||||
curl -s -X PATCH \
|
||||
-H "Authorization: token $GIST_TOKEN" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
"https://api.github.com/gists/$GIST_ID" \
|
||||
-d "{\"files\":{\"$filename\":{\"content\":$content}}}"
|
||||
|
||||
echo "✅ Uploaded $filename to Gist"
|
||||
done
|
||||
|
||||
- name: Check for significant changes
|
||||
id: check_changes
|
||||
run: |
|
||||
git diff --quiet docs/community-stats.zh.md docs/community-stats.md README.md README_CN.md || echo "changed=true" >> $GITHUB_OUTPUT
|
||||
# Only commit if there are changes to markdown files (not just time updates)
|
||||
# This reduces commit frequency by only committing when actual data changes
|
||||
|
||||
# Get current stats
|
||||
NEW_DOWNLOADS=$(jq -r '.total_downloads' docs/community-stats.json 2>/dev/null || echo "0")
|
||||
NEW_POSTS=$(jq -r '.total_posts' docs/community-stats.json 2>/dev/null || echo "0")
|
||||
|
||||
# Get previous stats from git
|
||||
OLD_DOWNLOADS=$(git show HEAD:docs/community-stats.json 2>/dev/null | jq -r '.total_downloads' 2>/dev/null || echo "0")
|
||||
OLD_POSTS=$(git show HEAD:docs/community-stats.json 2>/dev/null | jq -r '.total_posts' 2>/dev/null || echo "0")
|
||||
|
||||
echo "Previous: $OLD_DOWNLOADS downloads, $OLD_POSTS posts"
|
||||
echo "Current: $NEW_DOWNLOADS downloads, $NEW_POSTS posts"
|
||||
|
||||
# Only mark as changed if downloads or posts count changed
|
||||
if [ "$NEW_DOWNLOADS" != "$OLD_DOWNLOADS" ] || [ "$NEW_POSTS" != "$OLD_POSTS" ]; then
|
||||
echo "changed=true" >> $GITHUB_OUTPUT
|
||||
echo "📊 Stats changed, will commit"
|
||||
else
|
||||
echo "changed=false" >> $GITHUB_OUTPUT
|
||||
echo "⏭️ No significant changes, skipping commit"
|
||||
fi
|
||||
|
||||
- name: Commit and push changes
|
||||
if: steps.check_changes.outputs.changed == 'true'
|
||||
|
||||
@@ -331,6 +331,67 @@ class OpenWebUIStats:
|
||||
json.dump(stats, f, ensure_ascii=False, indent=2)
|
||||
print(f"✅ JSON 数据已保存到: {filepath}")
|
||||
|
||||
def generate_shields_endpoints(self, stats: dict, output_dir: str = "docs/badges"):
|
||||
"""
|
||||
生成 Shields.io endpoint JSON 文件
|
||||
|
||||
Args:
|
||||
stats: 统计数据
|
||||
output_dir: 输出目录
|
||||
"""
|
||||
Path(output_dir).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def format_number(n: int) -> str:
|
||||
"""格式化数字为易读格式"""
|
||||
if n >= 1000000:
|
||||
return f"{n/1000000:.1f}M"
|
||||
elif n >= 1000:
|
||||
return f"{n/1000:.1f}k"
|
||||
return str(n)
|
||||
|
||||
# 各种徽章数据
|
||||
badges = {
|
||||
"downloads": {
|
||||
"schemaVersion": 1,
|
||||
"label": "downloads",
|
||||
"message": format_number(stats["total_downloads"]),
|
||||
"color": "blue",
|
||||
"namedLogo": "openwebui",
|
||||
},
|
||||
"plugins": {
|
||||
"schemaVersion": 1,
|
||||
"label": "plugins",
|
||||
"message": str(stats["total_posts"]),
|
||||
"color": "green",
|
||||
},
|
||||
"followers": {
|
||||
"schemaVersion": 1,
|
||||
"label": "followers",
|
||||
"message": format_number(stats.get("user", {}).get("followers", 0)),
|
||||
"color": "blue",
|
||||
},
|
||||
"points": {
|
||||
"schemaVersion": 1,
|
||||
"label": "points",
|
||||
"message": format_number(stats.get("user", {}).get("total_points", 0)),
|
||||
"color": "orange",
|
||||
},
|
||||
"upvotes": {
|
||||
"schemaVersion": 1,
|
||||
"label": "upvotes",
|
||||
"message": format_number(stats["total_upvotes"]),
|
||||
"color": "brightgreen",
|
||||
},
|
||||
}
|
||||
|
||||
for name, data in badges.items():
|
||||
filepath = Path(output_dir) / f"{name}.json"
|
||||
with open(filepath, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
print(f" 📊 Generated badge: {name}.json")
|
||||
|
||||
print(f"✅ Shields.io endpoints saved to: {output_dir}/")
|
||||
|
||||
def generate_readme_stats(self, stats: dict, lang: str = "zh") -> str:
|
||||
"""
|
||||
生成 README 统计徽章区域
|
||||
@@ -537,6 +598,10 @@ def main():
|
||||
json_path = script_dir / "docs" / "community-stats.json"
|
||||
stats_client.save_json(stats, str(json_path))
|
||||
|
||||
# 生成 Shields.io endpoint JSON (用于动态徽章)
|
||||
badges_dir = script_dir / "docs" / "badges"
|
||||
stats_client.generate_shields_endpoints(stats, str(badges_dir))
|
||||
|
||||
# 更新 README 文件
|
||||
readme_path = script_dir / "README.md"
|
||||
readme_cn_path = script_dir / "README_CN.md"
|
||||
|
||||
Reference in New Issue
Block a user