diff --git a/.gitea/workflows/update_stats_badge.yaml b/.gitea/workflows/update_stats_badge.yaml new file mode 100644 index 0000000..e438bcd --- /dev/null +++ b/.gitea/workflows/update_stats_badge.yaml @@ -0,0 +1,929 @@ +name: Update Stats Badege + +on: + push: + branches: [main, master] + workflow_dispatch: + +# ========================================== +# 🔧 配置区域 - 根据你的项目修改 +# ========================================== +env: + # ===== Token 配置 ===== + # 优先使用 STATS_TOKEN,不存在则使用 GITHUB_TOKEN + # 建议在 Settings -> Secrets 中配置 STATS_TOKEN 以获得更好的权限控制 + ACCESS_TOKEN: ${{ secrets.STATS_TOKEN }} + + # ===== 工作区配置 ===== + # 完整克隆的工作目录 + WORKSPACE_DIR: '/home/workspace/' + + # ===== 分支配置 ===== + # 徽章数据存储分支(可配置) + BADGE_BRANCH: 'stats' + # 徽章文件存储目录 + BADGE_DIR: 'badges' + + # ===== 排除配置 ===== + # 全局排除的目录(这些目录会被完全忽略) + EXCLUDE_DIRS: 'node_modules,dist,build,out,target,vendor,.venv,venv,__pycache__,.git,.github' + + # 特殊包含规则(即使在排除目录中,也统计这些扩展名的文件) + # 格式: 目录:扩展名列表 + # 例如: 'dist:js,css' 表示即使 dist 被排除,也统计其中的 .js 和 .css 文件 + SPECIAL_INCLUDES: '' + # 示例: 'dist:js,css|vendor:go,mod' + + # ===== 徽章颜色配置 ===== + COLOR_TOTAL: 'blue' + COLOR_FILES: 'green' + COLOR_DEFAULT: 'brightgreen' + + # ===== 徽章样式配置 ===== + BADGE_STYLE: 'flat' # 可选: flat, flat-square, plastic, for-the-badge, social + + # ===== 输出配置 ===== + # 是否生成详细报告 + GENERATE_DETAILED_REPORT: 'true' + # 是否输出到 workflow summary + OUTPUT_TO_SUMMARY: 'true' + # 最小代码行数阈值(低于此值的语言不生成徽章) + MIN_LINES_THRESHOLD: '10' + + # ===== Git 配置 ===== + GIT_USER_NAME: 'github-actions[bot]' + GIT_USER_EMAIL: 'github-actions[bot]@users.noreply.github.com' + +# ========================================== +# 🎨 语言分组配置 +# 格式: 组名:后缀列表:显示名称:颜色:图标(可选) +# 图标使用 simple-icons 的名称,如 cplusplus, typescript 等 +# ========================================== + LANGUAGE_GROUPS: | + cpp:hpp,cpp,cxx,cc,h,c:C/C++:00599C:cplusplus + python:py:Python:3572A5:python + typescript:ts,tsx:TypeScript:3178c6:typescript + javascript:js,jsx:JavaScript:F7DF1E:javascript + java:java:Java:007396:java + go:go:Go:00ADD8:go + rust:rs:Rust:CE412B:rust + shell:sh,bash:Shell:4EAA25:gnubash + yaml:yml,yaml:YAML:CB171E + tsf:tsl,tsf:TSF:9945FF + +jobs: + update-stats: + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: 🔍 验证 Token 配置 + id: validate_token + run: | + echo "🔐 验证访问令牌..." + + if [ -z "${{ env.ACCESS_TOKEN }}" ]; then + echo "❌ 错误: 未配置访问令牌" + echo "请在 Settings -> Secrets 中配置 STATS_TOKEN 或确保 GITHUB_TOKEN 可用" + exit 1 + fi + + # 检测使用的是哪个 token + if [ -n "${{ secrets.STATS_TOKEN }}" ]; then + echo "✅ 使用自定义 STATS_TOKEN" + echo "token_type=STATS_TOKEN" >> $GITHUB_OUTPUT + else + echo "✅ 使用默认 GITHUB_TOKEN" + echo "token_type=GITHUB_TOKEN" >> $GITHUB_OUTPUT + fi + + echo "🔗 仓库: ${{ github.repository }}" + echo "🌿 分支: ${{ github.ref_name }}" + echo "📝 提交: ${GITHUB_SHA:0:7}" + + - name: 📥 克隆主仓库(完整模式) + id: clone_main + run: | + echo "======================================" + echo "🚀 开始克隆主仓库" + echo "======================================" + + REPO_NAME="${{ github.event.repository.name }}" + REPO_DIR="${{ env.WORKSPACE_DIR }}/$REPO_NAME" + + echo "📁 仓库名称: $REPO_NAME" + echo "📍 目标目录: $REPO_DIR" + echo "🌐 服务器: ${GITHUB_SERVER_URL}" + echo "" + + # 清理旧的工作目录 + if [ -d "$REPO_DIR" ]; then + echo "🧹 清理已存在的目录..." + rm -rf "$REPO_DIR" + fi + + # 创建工作目录 + mkdir -p "${{ env.WORKSPACE_DIR }}" + + # 克隆仓库(使用 TOKEN) + echo "📥 克隆仓库..." + git clone \ + --depth 0 \ + --single-branch \ + --branch ${{ github.ref_name }} \ + https://oauth2:${{ env.ACCESS_TOKEN }}@${GITHUB_SERVER_URL#https://}/${{ github.repository }}.git \ + "$REPO_DIR" + + if [ $? -ne 0 ]; then + echo "❌ 克隆失败" + exit 1 + fi + + cd "$REPO_DIR" + + echo "✅ 仓库克隆成功" + echo "" + + # 配置 Git 用户信息 + echo "⚙️ 配置 Git 用户信息..." + git config user.name "${{ env.GIT_USER_NAME }}" + git config user.email "${{ env.GIT_USER_EMAIL }}" + + # 显示仓库信息 + echo "📊 仓库信息:" + echo " - 当前分支: $(git branch --show-current)" + echo " - 最新提交: $(git log -1 --oneline)" + echo " - 远程地址: $(git remote get-url origin | sed 's/oauth2:.*@/oauth2:***@/')" + echo "" + + # 导出环境变量 + echo "REPO_DIR=$REPO_DIR" >> $GITHUB_ENV + echo "REPO_NAME=$REPO_NAME" >> $GITHUB_ENV + + echo "✅ 主仓库准备完成" + echo "======================================" + echo "" + + - name: 🔧 准备统计分支 + id: prepare_stats_branch + run: | + echo "======================================" + echo "🔧 准备统计分支" + echo "======================================" + + cd "${{ env.REPO_DIR }}" + + # 获取所有远程分支 + git fetch origin --prune + + # 检查统计分支是否存在 + if git ls-remote --heads origin ${{ env.BADGE_BRANCH }} | grep -q ${{ env.BADGE_BRANCH }}; then + echo "✅ 统计分支 '${{ env.BADGE_BRANCH }}' 已存在" + + # 检出统计分支 + git fetch origin ${{ env.BADGE_BRANCH }}:${{ env.BADGE_BRANCH }} + git checkout ${{ env.BADGE_BRANCH }} + + echo "📂 当前分支内容:" + ls -la + + # 返回主分支 + git checkout ${{ github.ref_name }} + + echo "branch_exists=true" >> $GITHUB_OUTPUT + else + echo "🆕 统计分支 '${{ env.BADGE_BRANCH }}' 不存在,将创建" + echo "branch_exists=false" >> $GITHUB_OUTPUT + fi + + echo "======================================" + echo "" + + - name: 🆕 创建统计分支(如需要) + if: steps.prepare_stats_branch.outputs.branch_exists == 'false' + run: | + echo "======================================" + echo "🆕 创建新的统计分支" + echo "======================================" + + cd "${{ env.REPO_DIR }}" + + # 创建孤立分支 + git checkout --orphan ${{ env.BADGE_BRANCH }} + + # 清空所有文件 + git rm -rf . 2>/dev/null || true + rm -rf * .* 2>/dev/null || true + + # 创建初始 README + cat > README.md << 'EOF' + # 📊 代码统计徽章数据 + + > 此分支由 GitHub Actions 自动生成和维护 + > + > ⚠️ **请勿手动修改此分支的内容!** + + ## 📁 目录结构 + + ``` + badges/ + ├── total-lines.json # 总代码行数徽章 + ├── total-files.json # 总文件数徽章 + ├── {language}-lines.json # 各语言代码行数徽章 + ├── {language}-files.json # 各语言文件数徽章 + └── README.md # 详细统计报告 + ``` + + ## 🔄 更新机制 + + - ✅ 每次 push 到主分支时自动更新 + - ✅ 每天 UTC 02:00 定时更新 + - ✅ 可通过 workflow_dispatch 手动触发 + + ## 📊 数据来源 + + 统计数据由 [cloc](https://github.com/AlDanial/cloc) 工具生成,包含以下信息: + + - 代码行数(不含注释和空行) + - 文件数量 + - 各编程语言占比 + + ## 🎨 徽章使用 + + 请查看 `badges/README.md` 获取详细的徽章使用说明。 + + --- + + *🤖 自动生成于: $(date -u '+%Y-%m-%d %H:%M:%S UTC')* + EOF + + # 添加并提交 + git add README.md + git commit -m "chore: 初始化统计分支 ${{ env.BADGE_BRANCH }}" + + # 推送到远程 + echo "📤 推送到远程..." + git push https://oauth2:${{ env.ACCESS_TOKEN }}@${GITHUB_SERVER_URL#https://}/${{ github.repository }}.git ${{ env.BADGE_BRANCH }} + + if [ $? -eq 0 ]; then + echo "✅ 统计分支创建成功" + else + echo "❌ 推送失败" + exit 1 + fi + + # 返回主分支 + git checkout ${{ github.ref_name }} + + echo "======================================" + echo "" + + - name: 🔍 检查并安装依赖 + id: check_deps + run: | + echo "======================================" + echo "🔍 检查必要的工具" + echo "======================================" + + MISSING_TOOLS=() + + # 检查 cloc + if ! command -v cloc &> /dev/null; then + echo "⚠️ cloc 未安装" + MISSING_TOOLS+=("cloc") + else + echo "✅ cloc 已安装: $(cloc --version | head -n1)" + fi + + # 检查 jq + if ! command -v jq &> /dev/null; then + echo "⚠️ jq 未安装" + MISSING_TOOLS+=("jq") + else + echo "✅ jq 已安装: $(jq --version)" + fi + + # 检查 bc + if ! command -v bc &> /dev/null; then + echo "⚠️ bc 未安装" + MISSING_TOOLS+=("bc") + else + echo "✅ bc 已安装" + fi + + echo "" + + # 如果有缺失的工具,进行安装 + if [ ${#MISSING_TOOLS[@]} -gt 0 ]; then + echo "📦 安装缺失的工具: ${MISSING_TOOLS[*]}" + sudo apt-get update -qq + sudo apt-get install -y ${MISSING_TOOLS[@]} + echo "✅ 工具安装完成" + echo "installed=true" >> $GITHUB_OUTPUT + else + echo "✅ 所有必要工具已就绪" + echo "installed=false" >> $GITHUB_OUTPUT + fi + + echo "" + echo "📋 最终工具版本:" + echo " - cloc: $(cloc --version | head -n1)" + echo " - jq: $(jq --version)" + echo " - bc: $(bc --version | head -n1)" + + echo "======================================" + echo "" + + - name: 📊 统计总代码行数 + id: total + run: | + echo "======================================" + echo "📊 统计总代码行数" + echo "======================================" + + cd "${{ env.REPO_DIR }}" + + # 构建排除参数 + EXCLUDE_ARG="" + if [ -n "${{ env.EXCLUDE_DIRS }}" ]; then + EXCLUDE_ARG="--exclude-dir=$(echo "${{ env.EXCLUDE_DIRS }}" | sed 's/ //g')" + fi + + echo "🔍 统计参数:" + echo " - 目录: $(pwd)" + echo " - 排除: ${{ env.EXCLUDE_DIRS }}" + echo "" + + # 执行统计 + echo "⏳ 正在统计..." + cloc . $EXCLUDE_ARG --json > /tmp/total_stats.json || { + echo "⚠️ cloc 执行失败,使用备用方案" + echo '{"SUM":{"code":0},"header":{"n_files":0}}' > /tmp/total_stats.json + } + + TOTAL_CODE=$(jq '.SUM.code // 0' /tmp/total_stats.json) + TOTAL_FILES=$(jq '.header.n_files // 0' /tmp/total_stats.json) + + # 格式化数字(添加千位分隔符) + format_num() { + printf "%'d" "$1" 2>/dev/null || echo "$1" + } + + echo "total_code=$TOTAL_CODE" >> $GITHUB_OUTPUT + echo "total_files=$TOTAL_FILES" >> $GITHUB_OUTPUT + echo "formatted_code=$(format_num $TOTAL_CODE)" >> $GITHUB_OUTPUT + echo "formatted_files=$(format_num $TOTAL_FILES)" >> $GITHUB_OUTPUT + + echo "" + echo "📈 统计结果:" + echo " - 总代码行数: $(format_num $TOTAL_CODE) 行" + echo " - 总文件数: $(format_num $TOTAL_FILES) 个" + + # 保存原始数据供后续使用 + cat /tmp/total_stats.json | jq '.' > /tmp/total_stats_backup.json + + echo "======================================" + echo "" + + - name: 📊 按语言分组统计 + id: languages + run: | + echo "======================================" + echo "📊 按语言分组统计" + echo "======================================" + + cd "${{ env.REPO_DIR }}" + + # 构建排除参数 + EXCLUDE_ARG="" + if [ -n "${{ env.EXCLUDE_DIRS }}" ]; then + EXCLUDE_ARG="--exclude-dir=$(echo "${{ env.EXCLUDE_DIRS }}" | sed 's/ //g')" + fi + + # 创建临时目录 + mkdir -p /tmp/lang_stats + rm -f /tmp/lang_summary.txt + + # 格式化数字函数 + format_num() { + printf "%'d" "$1" 2>/dev/null || echo "$1" + } + + # 读取语言分组配置并统计 + LANG_COUNT=0 + MIN_THRESHOLD=${{ env.MIN_LINES_THRESHOLD }} + + echo "⚙️ 配置信息:" + echo " - 最小阈值: $MIN_THRESHOLD 行" + echo "" + + echo "${{ env.LANGUAGE_GROUPS }}" | while IFS= read -r line; do + [ -z "$line" ] && continue + + # 解析配置: 组名:后缀:显示名:颜色:图标(可选) + LANG_ID=$(echo "$line" | cut -d':' -f1 | tr -d ' ') + EXTENSIONS=$(echo "$line" | cut -d':' -f2 | tr -d ' ') + DISPLAY_NAME=$(echo "$line" | cut -d':' -f3 | tr -d ' ') + COLOR=$(echo "$line" | cut -d':' -f4 | tr -d ' ') + ICON=$(echo "$line" | cut -d':' -f5 | tr -d ' ') + + [ -z "$LANG_ID" ] && continue + + echo "📝 统计 $DISPLAY_NAME ($EXTENSIONS)..." + + # 统计该语言组 + cloc . $EXCLUDE_ARG \ + --include-ext="$EXTENSIONS" \ + --json > /tmp/lang_stats/${LANG_ID}.json 2>/dev/null || { + echo " ⚠️ 统计失败,跳过" + continue + } + + CODE_LINES=$(jq '.SUM.code // 0' /tmp/lang_stats/${LANG_ID}.json) + FILE_COUNT=$(jq '.header.n_files // 0' /tmp/lang_stats/${LANG_ID}.json) + + # 如果代码行数低于阈值,跳过 + if [ "$CODE_LINES" -lt "$MIN_THRESHOLD" ]; then + echo " ⏭️ 代码行数 ($CODE_LINES) 低于阈值,跳过" + continue + fi + + FORMATTED_LINES=$(format_num $CODE_LINES) + + echo " ✅ ${DISPLAY_NAME}: $FORMATTED_LINES 行 ($FILE_COUNT 文件)" + + # 保存数据(添加图标字段) + echo "${LANG_ID}|${DISPLAY_NAME}|${CODE_LINES}|${FORMATTED_LINES}|${FILE_COUNT}|${COLOR}|${ICON}" >> /tmp/lang_summary.txt + done + + echo "" + + # 统计有效语言数量 + if [ -f /tmp/lang_summary.txt ]; then + VALID_LANG_COUNT=$(wc -l < /tmp/lang_summary.txt) + echo "language_count=$VALID_LANG_COUNT" >> $GITHUB_OUTPUT + echo "✅ 语言统计完成: $VALID_LANG_COUNT 种语言" + else + echo "language_count=0" >> $GITHUB_OUTPUT + echo "⚠️ 未找到符合条件的语言" + fi + + echo "======================================" + echo "" + + - name: 🎨 生成徽章数据 + id: generate_badges + run: | + echo "======================================" + echo "🎨 生成徽章数据" + echo "======================================" + + cd "${{ env.REPO_DIR }}" + + # 切换到统计分支 + echo "🔄 切换到统计分支..." + git fetch origin ${{ env.BADGE_BRANCH }}:${{ env.BADGE_BRANCH }} + git checkout ${{ env.BADGE_BRANCH }} + + # 创建徽章目录 + mkdir -p ${{ env.BADGE_DIR }} + + # 清理旧的徽章文件 + echo "🧹 清理旧徽章..." + rm -f ${{ env.BADGE_DIR }}/*.json + + GENERATED_COUNT=0 + + echo "" + echo "📝 生成徽章文件..." + + # 1. 总代码行数徽章 + cat > ${{ env.BADGE_DIR }}/total-lines.json << EOF + { + "schemaVersion": 1, + "label": "总代码", + "message": "${{ steps.total.outputs.formatted_code }} 行", + "color": "${{ env.COLOR_TOTAL }}", + "style": "${{ env.BADGE_STYLE }}" + } + EOF + GENERATED_COUNT=$((GENERATED_COUNT + 1)) + echo " ✅ total-lines.json" + + # 2. 总文件数徽章 + cat > ${{ env.BADGE_DIR }}/total-files.json << EOF + { + "schemaVersion": 1, + "label": "文件数", + "message": "${{ steps.total.outputs.formatted_files }} 个", + "color": "${{ env.COLOR_FILES }}", + "style": "${{ env.BADGE_STYLE }}" + } + EOF + GENERATED_COUNT=$((GENERATED_COUNT + 1)) + echo " ✅ total-files.json" + + # 3. 为每个语言生成徽章 + if [ -f /tmp/lang_summary.txt ]; then + while IFS='|' read -r lang_id display_name code_lines formatted_lines file_count color icon; do + [ -z "$lang_id" ] && continue + + # 使用默认颜色(如果未指定) + [ -z "$color" ] && color="${{ env.COLOR_DEFAULT }}" + + # 语言代码行数徽章 + cat > ${{ env.BADGE_DIR }}/${lang_id}-lines.json << EOF + { + "schemaVersion": 1, + "label": "${display_name}", + "message": "${formatted_lines} 行", + "color": "${color}", + "style": "${{ env.BADGE_STYLE }}" + } + EOF + GENERATED_COUNT=$((GENERATED_COUNT + 1)) + + # 语言文件数徽章 + cat > ${{ env.BADGE_DIR }}/${lang_id}-files.json << EOF + { + "schemaVersion": 1, + "label": "${display_name} 文件", + "message": "${file_count} 个", + "color": "${color}", + "style": "${{ env.BADGE_STYLE }}" + } + EOF + GENERATED_COUNT=$((GENERATED_COUNT + 1)) + + echo " ✅ ${lang_id}-lines.json, ${lang_id}-files.json" + done < /tmp/lang_summary.txt + fi + + echo "generated_count=$GENERATED_COUNT" >> $GITHUB_OUTPUT + + echo "" + echo "📊 生成统计:" + echo " - 总计: $GENERATED_COUNT 个徽章文件" + echo "" + echo "📂 徽章文件列表:" + ls -lh ${{ env.BADGE_DIR }}/*.json 2>/dev/null || echo " ⚠️ 未找到徽章文件" + + echo "======================================" + echo "" + + - name: 📄 生成统计报告 + if: env.GENERATE_DETAILED_REPORT == 'true' + run: | + echo "======================================" + echo "📄 生成详细统计报告" + echo "======================================" + + cd "${{ env.REPO_DIR }}" + + TOTAL_CODE=${{ steps.total.outputs.total_code }} + REPO_NAME="${{ env.REPO_NAME }}" + REPO_OWNER="${{ github.repository_owner }}" + + echo "📝 生成 README.md..." + + # 生成 Markdown 报告 + cat > ${{ env.BADGE_DIR }}/README.md << EOFMD + # 📊 ${REPO_NAME} 代码统计报告 + + > 最后更新: $(date '+%Y-%m-%d %H:%M:%S %Z') + > + > 分支: \`${{ github.ref_name }}\` | 提交: [\`${GITHUB_SHA:0:7}\`](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commit/${GITHUB_SHA}) + + ## 📈 总览 + + | 指标 | 数值 | + |------|------| + | 💻 **总代码行数** | ${{ steps.total.outputs.formatted_code }} | + | 📁 **总文件数** | ${{ steps.total.outputs.formatted_files }} | + | 🌐 **语言种类** | ${{ steps.languages.outputs.language_count }} | + | 🎨 **徽章数量** | ${{ steps.generate_badges.outputs.generated_count }} | + + ## 🎨 各语言统计 + + EOFMD + + # 检查是否有语言数据 + if [ -f /tmp/lang_summary.txt ] && [ -s /tmp/lang_summary.txt ]; then + cat >> ${{ env.BADGE_DIR }}/README.md << 'EOFMD' + | 语言 | 代码行数 | 文件数 | 占比 | 进度条 | + |------|----------|--------|------|--------| + EOFMD + + # 添加各语言数据(按代码行数排序) + sort -t'|' -k3 -nr /tmp/lang_summary.txt | while IFS='|' read -r lang_id display_name code_lines formatted_lines file_count color icon; do + [ -z "$lang_id" ] && continue + + # 计算百分比 + if [ "$TOTAL_CODE" -gt 0 ]; then + PERCENT=$(echo "scale=1; $code_lines * 100 / $TOTAL_CODE" | bc) + else + PERCENT="0.0" + fi + + # 生成进度条(每2%一个方块) + BAR_LENGTH=$(echo "scale=0; $PERCENT / 2" | bc) + BAR_LENGTH=${BAR_LENGTH:-0} + if [ "$BAR_LENGTH" -gt 0 ]; then + BAR=$(printf '█%.0s' $(seq 1 $BAR_LENGTH)) + else + BAR="░" + fi + + # 添加图标(如果有) + ICON_DISPLAY="" + if [ -n "$icon" ]; then + ICON_DISPLAY="\"${display_name}\"/ " + fi + + echo "| ${ICON_DISPLAY}**${display_name}** | ${formatted_lines} | ${file_count} | ${PERCENT}% | ${BAR} |" >> ${{ env.BADGE_DIR }}/README.md + done + else + echo "" >> ${{ env.BADGE_DIR }}/README.md + echo "> ⚠️ 未找到符合统计条件的语言文件" >> ${{ env.BADGE_DIR }}/README.md + fi + + # 添加使用说明 + cat >> ${{ env.BADGE_DIR }}/README.md << EOFMD + + --- + + ## 📖 徽章使用指南 + + ### 🎯 总览徽章 + + \`\`\`markdown + ![总代码行数](https://img.shields.io/endpoint?url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/raw/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/total-lines.json) + ![总文件数](https://img.shields.io/endpoint?url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/raw/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/total-files.json) + \`\`\` + + **效果预览:** + + ![总代码行数](https://img.shields.io/endpoint?url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/raw/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/total-lines.json) + ![总文件数](https://img.shields.io/endpoint?url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/raw/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/total-files.json) + + ### 🌐 各语言徽章 + + EOFMD + + # 添加各语言徽章使用示例 + if [ -f /tmp/lang_summary.txt ] && [ -s /tmp/lang_summary.txt ]; then + while IFS='|' read -r lang_id display_name code_lines formatted_lines file_count color icon; do + [ -z "$lang_id" ] && continue + cat >> ${{ env.BADGE_DIR }}/README.md << EOFLANG + **${display_name}:** + + \`\`\`markdown + ![${display_name} 代码行数](https://img.shields.io/endpoint?url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/raw/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/${lang_id}-lines.json) + ![${display_name} 文件数](https://img.shields.io/endpoint?url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/raw/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/${lang_id}-files.json) + \`\`\` + + ![${display_name} 代码行数](https://img.shields.io/endpoint?url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/raw/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/${lang_id}-lines.json) + ![${display_name} 文件数](https://img.shields.io/endpoint?url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/raw/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/${lang_id}-files.json) + + EOFLANG + done < /tmp/lang_summary.txt + fi + + # 添加配置说明 + cat >> ${{ env.BADGE_DIR }}/README.md << 'EOFMD' + + --- + + ## ⚙️ 配置说明 + + ### Token 配置 + + - 当前使用: **${{ steps.validate_token.outputs.token_type }}** + - 推荐配置自定义 `STATS_TOKEN` 以获得更好的权限控制 + + ### 排除规则 + + 当前排除的目录: + \`\`\` + ${{ env.EXCLUDE_DIRS }} + \`\`\` + + ### 阈值设置 + + - 最小代码行数阈值: **${{ env.MIN_LINES_THRESHOLD }}** 行 + - 低于此阈值的语言将不会生成徽章 + + ### 徽章样式 + + - 当前样式: **${{ env.BADGE_STYLE }}** + - 可选样式: flat, flat-square, plastic, for-the-badge, social + + --- + +
+ + *📊 由 [GitHub Actions](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions) 自动生成和更新* + + *🤖 生成时间: $(date -u '+%Y-%m-%d %H:%M:%S UTC')* + +
+ EOFMD + + echo "✅ 详细统计报告已生成" + echo "======================================" + echo "" + + - name: 📤 提交并推送到统计分支 + id: commit + run: | + echo "======================================" + echo "📤 提交并推送更新" + echo "======================================" + + cd "${{ env.REPO_DIR }}" + + # 确保在统计分支 + git checkout ${{ env.BADGE_BRANCH }} + + # 配置 Git 用户信息 + git config user.name "${{ env.GIT_USER_NAME }}" + git config user.email "${{ env.GIT_USER_EMAIL }}" + + # 添加所有更改 + git add ${{ env.BADGE_DIR }}/ + + # 检查是否有变更 + if git diff --staged --quiet; then + echo "📌 没有变更,跳过提交" + echo "changed=false" >> $GITHUB_OUTPUT + echo "" + else + echo "📝 准备提交..." + + # 生成提交信息 + COMMIT_MSG="chore: 更新代码统计 [$(date '+%Y-%m-%d %H:%M')] + + 📊 统计摘要: + - 总代码: ${{ steps.total.outputs.formatted_code }} 行 + - 总文件: ${{ steps.total.outputs.formatted_files }} 个 + - 语言数: ${{ steps.languages.outputs.language_count }} 种 + - 徽章数: ${{ steps.generate_badges.outputs.generated_count }} 个 + + 🔗 触发提交: ${GITHUB_SHA:0:7} + 🤖 由 GitHub Actions 自动生成" + + git commit -m "$COMMIT_MSG" + + echo "📤 推送到远程 ${{ env.BADGE_BRANCH }} 分支..." + + # 推送到远程(使用 TOKEN) + git push https://oauth2:${{ env.ACCESS_TOKEN }}@${GITHUB_SERVER_URL#https://}/${{ github.repository }}.git ${{ env.BADGE_BRANCH }} + + if [ $? -eq 0 ]; then + echo "✅ 推送成功" + echo "changed=true" >> $GITHUB_OUTPUT + else + echo "❌ 推送失败" + exit 1 + fi + fi + + echo "======================================" + echo "" + + - name: 📊 生成 Workflow Summary + if: env.OUTPUT_TO_SUMMARY == 'true' && success() + run: | + cat >> $GITHUB_STEP_SUMMARY << 'EOFSUMMARY' + # 📊 代码统计完成 + + ## ✅ 执行结果 + + | 项目 | 结果 | + |------|------| + | 🔐 Token 类型 | **${{ steps.validate_token.outputs.token_type }}** | + | 🔧 依赖检查 | ${{ steps.check_deps.outputs.installed == 'true' && '✅ 已安装缺失工具' || '✅ 所有工具就绪' }} | + | 📊 总代码行数 | **${{ steps.total.outputs.formatted_code }}** 行 | + | 📁 总文件数 | **${{ steps.total.outputs.formatted_files }}** 个 | + | 🌐 语言种类 | **${{ steps.languages.outputs.language_count }}** 种 | + | 🎨 生成徽章 | **${{ steps.generate_badges.outputs.generated_count }}** 个 | + | 📤 提交状态 | ${{ steps.commit.outputs.changed == 'true' && '✅ 已更新' || '📌 无变更' }} | + + ## 🔗 快速链接 + + - 📊 [查看详细统计报告](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/README.md) + - 🎨 [浏览徽章文件](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}) + - 🔧 [查看 Workflow 配置](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/blob/${{ github.ref_name }}/.github/workflows/update_stats_badge.yaml) + + ## 📝 语言分布 + + EOFSUMMARY + + # 添加语言分布表格 + if [ -f /tmp/lang_summary.txt ] && [ -s /tmp/lang_summary.txt ]; then + cat >> $GITHUB_STEP_SUMMARY << 'EOFTABLE' + | 语言 | 代码行数 | 文件数 | 占比 | + |------|----------|--------|------| + EOFTABLE + + TOTAL_CODE=${{ steps.total.outputs.total_code }} + sort -t'|' -k3 -nr /tmp/lang_summary.txt | head -10 | while IFS='|' read -r lang_id display_name code_lines formatted_lines file_count color icon; do + [ -z "$lang_id" ] && continue + + if [ "$TOTAL_CODE" -gt 0 ]; then + PERCENT=$(echo "scale=1; $code_lines * 100 / $TOTAL_CODE" | bc) + else + PERCENT="0.0" + fi + + echo "| **${display_name}** | ${formatted_lines} | ${file_count} | ${PERCENT}% |" >> $GITHUB_STEP_SUMMARY + done + else + echo "" >> $GITHUB_STEP_SUMMARY + echo "> ⚠️ 未找到符合条件的语言文件" >> $GITHUB_STEP_SUMMARY + fi + + # 添加工作区信息 + cat >> $GITHUB_STEP_SUMMARY << 'EOFWS' + + ## 📂 工作区信息 + + | 项目 | 值 | + |------|-----| + | 📁 仓库名称 | `${{ env.REPO_NAME }}` | + | 📍 工作目录 | `${{ env.REPO_DIR }}` | + | 🌿 统计分支 | `${{ env.BADGE_BRANCH }}` | + | 📂 徽章目录 | `${{ env.BADGE_DIR }}` | + + EOFWS + + echo "" >> $GITHUB_STEP_SUMMARY + echo "---" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "*⏱️ 执行时间: $(date '+%Y-%m-%d %H:%M:%S %Z')*" >> $GITHUB_STEP_SUMMARY + + - name: 📋 输出使用说明 + if: success() + run: | + echo "================================================" + echo "✅ 代码统计任务执行完成!" + echo "================================================" + echo "" + + echo "🔐 Token 信息:" + echo " - 使用: ${{ steps.validate_token.outputs.token_type }}" + echo "" + + # 根据实际结果输出 + if [ "${{ steps.commit.outputs.changed }}" == "true" ]; then + echo "📊 统计结果:" + echo " - 总代码: ${{ steps.total.outputs.formatted_code }} 行" + echo " - 总文件: ${{ steps.total.outputs.formatted_files }} 个" + echo " - 语言数: ${{ steps.languages.outputs.language_count }} 种" + echo " - 徽章数: ${{ steps.generate_badges.outputs.generated_count }} 个" + echo "" + echo "📤 已推送更新到分支: ${{ env.BADGE_BRANCH }}" + else + echo "📌 统计数据无变更,未产生新的提交" + fi + + echo "" + echo "📂 工作区信息:" + echo " - 仓库目录: ${{ env.REPO_DIR }}" + echo " - 统计分支: ${{ env.BADGE_BRANCH }}" + echo "" + echo "🔗 查看详细报告:" + echo " ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/README.md" + echo "" + echo "🎨 徽章目录:" + echo " ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}" + echo "" + echo "================================================" + + # 如果有警告或特殊情况,也输出 + if [ "${{ steps.check_deps.outputs.installed }}" == "true" ]; then + echo "" + echo "ℹ️ 本次运行安装了缺失的依赖工具" + fi + + if [ "${{ steps.languages.outputs.language_count }}" == "0" ]; then + echo "" + echo "⚠️ 警告: 未找到符合条件的语言文件" + echo " 请检查 LANGUAGE_GROUPS 配置和 MIN_LINES_THRESHOLD 设置" + fi + + # 清理工作区(可选) + if [ "${{ env.CLEANUP_WORKSPACE }}" == "true" ]; then + echo "" + echo "🧹 清理工作区..." + rm -rf "${{ env.WORKSPACE_DIR }}" + echo "✅ 清理完成" + fi + + - name: 🧹 清理工作区 + if: always() + run: | + echo "🧹 清理临时文件..." + rm -rf /tmp/lang_stats /tmp/lang_summary.txt /tmp/total_stats*.json + echo "✅ 清理完成" \ No newline at end of file diff --git a/WORKFLOW.md b/WORKFLOW.md index 3c57234..3c9f6fc 100644 --- a/WORKFLOW.md +++ b/WORKFLOW.md @@ -9,6 +9,7 @@ ```txt .gitea/workflows/ ├── changelog-and-release.yml # CHANGELOG 生成 + Release 创建 +├── update_stats_badge.yml # 代码行数的统计 └── ... # 更多 workflow 待添加 ``` @@ -45,6 +46,36 @@ git push origin 1.0.0 --- +#### 2. 📊 代码统计徽章工作流 (`update-stats-badge.yml`) + +**功能**:自动统计代码行数并生成徽章数据 + +**特性**: + +- 📈 统计总代码行数和文件数 +- 🌐 按语言分组统计 +- 🎨 自动生成徽章 JSON 数据 +- 📊 生成统计摘要(JSON 格式) +- 🚫 灵活的目录排除配置 + +**触发方式**: + +```bash +# 推送到主分支时自动触发 +git push origin main + +# 手动触发 +# 仓库 → Actions → Update Code Statistics Badge → Run workflow +``` + +**配置文件**:[update-stats-badge.yml](.gitea/workflows/update_stats_badge.yaml) + +**markdown引用格式**: `![C++](https://img.shields.io/endpoint?url=https://你的gitea/用户名/仓库/raw/分支/stats/badges/cpp-lines.json)` + +💡 **详细配置**:查看 `update-stats-badge.yml` 文件顶部的 `env` 区域,包含语言分组、颜色、排除目录等配置 + +--- + ### 🔜 待扩展 更多自动化场景: