diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..f31e34c --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,31 @@ +categories: + - title: '🚀 新功能' + labels: ['feat', 'feature'] + - title: '🛠️ 修复' + labels: ['fix', 'bugfix'] + - title: '💅 样式' + labels: ['style'] + - title: '📄 文档' + labels: ['docs'] + - title: '⚡️ 性能' + labels: ['perf'] + - title: '🧪 测试' + labels: ['test'] + - title: '♻️ 重构' + labels: ['refactor'] + - title: '📦 构建' + labels: ['build'] + - title: '🚨 补丁' + labels: ['patch', 'hotfix'] + - title: '🌐 发布' + labels: ['release', 'publish'] + - title: '🔧 流程' + labels: ['ci', 'cd', 'workflow'] + - title: '⚙️ 配置' + labels: ['config', 'chore'] + - title: '📁 文件' + labels: ['file'] + - title: '🎨 格式化' + labels: ['format'] + - title: '🔀 其他' + labels: ['other', 'misc'] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c2887ab --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,119 @@ +name: Auto Release + +on: + push: + tags: + - 'v*' + +permissions: + contents: write + pull-requests: read + issues: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install yq + run: sudo snap install yq + + - name: Generate changelog + id: changelog + env: + CONFIG_FILE: .github/release.yml + run: | + # 解析配置文件 + declare -A category_map + while IFS=";" read -r title labels; do + for label in $labels; do + category_map[$label]="$title" + done + done < <(yq -o=tsv '.categories[] | [.title, (.labels | join(" "))] | join(";")' $CONFIG_FILE) + # 获取版本范围 + mapfile -t tags < <(git tag -l --sort=-version:refname) + current_tag=${tags[0]} + previous_tag=${tags[1]:-} + if [[ -z "$previous_tag" ]]; then + commit_range="$current_tag" + echo "首次发布版本: $current_tag" + else + commit_range="$previous_tag..$current_tag" + echo "版本范围: $commit_range" + fi + # 获取所有符合规范的提交 + commits=$(git log --pretty=format:"%s|%h" "$commit_range") + # 生成分类日志 + declare -A log_entries + while IFS="|" read -r subject hash; do + # type=$(echo "$subject" | cut -d':' -f1 | tr -d ' ') + type=$(echo "$subject" | sed -E 's/^([[:alnum:]]+)(\(.*\))?:.*/\1/' | tr -d ' ') + found=0 + for label in "${!category_map[@]}"; do + if [[ "$type" == "$label" ]]; then + entry="- ${subject} (${hash:0:7})" + log_entries[${category_map[$label]}]+="$entry"$'\n' + found=1 + break + fi + done + if [[ $found -eq 0 ]]; then + entry="- ${subject} (${hash:0:7})" + log_entries["其他"]+="$entry"$'\n' + fi + done <<< "$commits" + + # 统计提交数量 + commit_count=$(git log --oneline "$commit_range" | wc -l) + # 统计受影响的文件数量 + file_count=$(git diff --name-only "$commit_range" | wc -l) + # 统计贡献者信息 + contributor_stats=$(git shortlog -sn "$commit_range") + contributor_notes="" + while IFS= read -r line; do + commits=$(echo "$line" | awk '{print $1}') + name=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^ //') + contributor_notes+="- @${name} (${commits} commits)\n" + done <<< "$contributor_stats" + # 构建输出内容 + release_notes="## 版本更新日志 ($current_tag)\n\n" + while IFS= read -r category; do + if [[ -n "${log_entries[$category]}" ]]; then + release_notes+="### $category\n${log_entries[$category]}\n" + fi + done < <(yq '.categories[].title' $CONFIG_FILE) + # 构建输出内容 + release_notes="## 版本更新日志 ($current_tag)\n\n" + current_date=$(date +"%Y-%m-%d") + # 添加发布日期和下载统计信息 + release_notes+=" ### 📅 发布日期: ${current_date}\n" + while IFS= read -r category; do + if [[ -n "${log_entries[$category]}" ]]; then + release_notes+="### $category\n${log_entries[$category]}\n" + fi + done < <(yq '.categories[].title' $CONFIG_FILE) + + # 添加统计信息 + release_notes+="### 📊 统计信息\n" + release_notes+="- 本次发布包含 ${commit_count} 个提交\n" + release_notes+="- 影响 ${file_count} 个文件\n\n" + # 添加贡献者信息 + release_notes+="### 👥 贡献者\n" + release_notes+="感谢这些优秀的贡献者(按提交次数排序):\n" + release_notes+="${contributor_notes}\n" + release_notes+="---\n" + # 写入文件 + echo -e "$release_notes" > changelog.md + echo "生成日志内容:" + cat changelog.md + - name: Create Release + uses: ncipollo/release-action@v1 + with: + generateReleaseNotes: false + bodyFile: changelog.md + tag: ${{ github.ref_name }}