diff --git a/.github/cliff.toml b/.github/cliff.toml
new file mode 100644
index 00000000..e2c8fb9f
--- /dev/null
+++ b/.github/cliff.toml
@@ -0,0 +1,100 @@
+[remote.github]
+owner = "GeWuYou"
+repo = "GFramework"
+
+[changelog]
+header = ""
+
+body = """
+{%- macro remote_url() -%}
+https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
+{%- endmacro -%}
+
+{% macro has_release_highlight(commit) -%}
+{%- set highlighted = false -%}
+{%- if commit.remote and commit.remote.pr_labels -%}
+ {%- for label in commit.remote.pr_labels -%}
+ {%- if label == "release-highlight" or label == "highlight" -%}
+ {%- set highlighted = true -%}
+ {%- endif -%}
+ {%- endfor -%}
+{%- endif -%}
+{%- if not highlighted and commit.footers -%}
+ {%- for footer in commit.footers -%}
+ {%- if footer.token == "Release-Highlight" and footer.value | trim == "true" -%}
+ {%- set highlighted = true -%}
+ {%- endif -%}
+ {%- endfor -%}
+{%- endif -%}
+{{ highlighted }}
+{%- endmacro %}
+
+{% macro print_commit(commit) -%}
+- {{ commit.message | split(pat="\n") | first | trim | upper_first }}{% if commit.remote and commit.remote.username %} by @{{ commit.remote.username }}{% elif commit.author.name %} by {{ commit.author.name }}{% endif %}{% if commit.remote and commit.remote.pr_number %} in [#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }}){% endif %}
+{%- endmacro %}
+
+{% if version -%}
+## {{ version }} ({{ timestamp | date(format="%Y-%m-%d") }})
+{% else -%}
+## 未发布
+{% endif %}
+
+{% set highlights = commits | filter(attribute="breaking", value=true) %}
+{% for commit in commits -%}
+ {% if self::has_release_highlight(commit=commit) == "true" -%}
+ {% set_global highlights = highlights | concat(with=commit) -%}
+ {% endif -%}
+{% endfor -%}
+
+{% if highlights | length > 0 -%}
+## 重点条目
+{% for commit in highlights -%}
+{{ self::print_commit(commit=commit) }}
+{% endfor %}
+
+{% endif -%}
+
+## What's Changed
+{% for commit in commits -%}
+{{ self::print_commit(commit=commit) }}
+{% endfor %}
+
+{% for group, commits in commits | group_by(attribute="group") -%}
+### {{ group | striptags | trim }}
+{% for commit in commits -%}
+{{ self::print_commit(commit=commit) }}
+{% endfor %}
+
+{% endfor -%}
+
+{% if previous and previous.version and version -%}
+Full Changelog: [{{ previous.version }}...{{ version }}]({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})
+{% endif -%}
+"""
+
+footer = ""
+
+[git]
+conventional_commits = true
+filter_unconventional = true
+split_commits = false
+protect_breaking_commits = false
+sort_commits = "oldest"
+
+commit_parsers = [
+ { message = ".*\\[skip changelog\\].*", skip = true },
+ { body = ".*\\[skip changelog\\].*", skip = true },
+ { message = "^feat", group = "✨ 新功能" },
+ { message = "^fix", group = "🐛 Bug 修复" },
+ { message = "^perf", group = "⚡ 优化" },
+ { message = "^refactor", group = "⚡ 优化" },
+ { message = "^docs", group = "📝 文档/其他" },
+ { message = "^test", group = "📝 文档/其他" },
+ { message = "^chore", group = "📝 文档/其他" },
+ { message = "^build", group = "📝 文档/其他" },
+ { message = "^ci", group = "📝 文档/其他" },
+ { message = "^style", group = "📝 文档/其他" }
+]
+
+[git.github]
+commits = true
diff --git a/.github/workflows/auto-tag.yml b/.github/workflows/auto-tag.yml
index 4e6b6017..b48915ed 100644
--- a/.github/workflows/auto-tag.yml
+++ b/.github/workflows/auto-tag.yml
@@ -56,13 +56,27 @@ jobs:
echo "next_version=${{ steps.semantic_release.outputs.new_release_version }}"
echo "next_tag=${{ steps.semantic_release.outputs.new_release_git_tag }}"
+ - name: Generate preview release notes
+ if: ${{ steps.semantic_release.outputs.new_release_published == 'true' }}
+ id: cliff_preview
+ uses: orhun/git-cliff-action@v4
+ with:
+ config: .github/cliff.toml
+ args: >-
+ -vv --unreleased --strip header
+ --tag "${{ steps.semantic_release.outputs.new_release_git_tag }}"
+ env:
+ OUTPUT: PREVIEW_RELEASE_NOTES.md
+ GITHUB_REPO: ${{ github.repository }}
+ GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
+
- name: Write preview summary
env:
RELEASE_PUBLISHED: ${{ steps.semantic_release.outputs.new_release_published }}
- RELEASE_NOTES: ${{ steps.semantic_release.outputs.new_release_notes }}
+ CLIFF_RELEASE_NOTES: ${{ steps.cliff_preview.outputs.content }}
run: |
{
- echo "## Semantic Release Preview"
+ echo "## Release Preview"
echo
echo "- Commit: \`${{ github.sha }}\`"
echo "- Release needed: \`${{ steps.semantic_release.outputs.new_release_published }}\`"
@@ -71,13 +85,11 @@ jobs:
echo "- Next tag: \`${{ steps.semantic_release.outputs.new_release_git_tag }}\`"
echo "- Preview auth: uses \`PAT_TOKEN\` because semantic-release dry-run still performs a remote push permission probe."
echo "- Snapshot semantics: this preview is pinned to dispatch SHA \`${{ github.sha }}\`; commits added to \`main\` after the run starts are not included."
- if [ "${RELEASE_PUBLISHED}" = "true" ] && [ -n "${RELEASE_NOTES}" ]; then
+ if [ "${RELEASE_PUBLISHED}" = "true" ] && [ -n "${CLIFF_RELEASE_NOTES}" ]; then
echo
- echo "Preview release notes
"
+ echo "### 候选发布说明"
echo
- printf '%s\n' "${RELEASE_NOTES}"
- echo
- echo " "
+ printf '%s\n' "${CLIFF_RELEASE_NOTES}"
fi
echo
echo "If the version looks correct, approve the \`release-approval\` environment to continue."
@@ -131,13 +143,26 @@ jobs:
echo "next_version=${{ steps.semantic_release.outputs.new_release_version }}"
echo "next_tag=${{ steps.semantic_release.outputs.new_release_git_tag }}"
+ - name: Generate published release notes
+ if: ${{ steps.semantic_release.outputs.new_release_published == 'true' }}
+ id: cliff_release
+ uses: orhun/git-cliff-action@v4
+ with:
+ config: .github/cliff.toml
+ args: >-
+ -vv --latest --strip header
+ env:
+ OUTPUT: PUBLISHED_RELEASE_NOTES.md
+ GITHUB_REPO: ${{ github.repository }}
+ GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
+
- name: Write release summary
env:
RELEASE_PUBLISHED: ${{ steps.semantic_release.outputs.new_release_published }}
- RELEASE_NOTES: ${{ steps.semantic_release.outputs.new_release_notes }}
+ CLIFF_RELEASE_NOTES: ${{ steps.cliff_release.outputs.content }}
run: |
{
- echo "## Semantic Release Publish"
+ echo "## Release Publish"
echo
echo "- Commit: \`${{ github.sha }}\`"
echo "- Preview last tag: \`${{ needs.preview.outputs.last_tag }}\`"
@@ -148,12 +173,10 @@ jobs:
echo "- Next version: \`${{ steps.semantic_release.outputs.new_release_version }}\`"
echo "- Next tag: \`${{ steps.semantic_release.outputs.new_release_git_tag }}\`"
echo "- Snapshot semantics: this publish run still uses dispatch SHA \`${{ github.sha }}\`; commits added to \`main\` after the preview started are excluded."
- if [ "${RELEASE_PUBLISHED}" = "true" ] && [ -n "${RELEASE_NOTES}" ]; then
+ if [ "${RELEASE_PUBLISHED}" = "true" ] && [ -n "${CLIFF_RELEASE_NOTES}" ]; then
echo
- echo "Published release notes
"
+ echo "### 已发布说明"
echo
- printf '%s\n' "${RELEASE_NOTES}"
- echo
- echo " "
+ printf '%s\n' "${CLIFF_RELEASE_NOTES}"
fi
} >> "${GITHUB_STEP_SUMMARY}"
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index e1287f3e..f9844bea 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -242,25 +242,53 @@ jobs:
packages: read
steps:
+ - name: Checkout repository (at tag)
+ uses: actions/checkout@v6
+ with:
+ fetch-depth: 0
+ persist-credentials: true
+
- name: Download package artifacts
uses: actions/download-artifact@v8
with:
name: packages
path: ./packages
+ - name: Generate release notes
+ id: cliff_release
+ uses: orhun/git-cliff-action@v4
+ with:
+ config: .github/cliff.toml
+ args: >-
+ -vv --latest --strip header
+ env:
+ OUTPUT: RELEASE_NOTES.md
+ GITHUB_REPO: ${{ github.repository }}
+ GITHUB_TOKEN: ${{ github.token }}
+
# 无论某一侧包源发布是否失败,都继续创建 Release。
# 合规工件由独立 workflow 生成,当前发布流不再假设这些文件在同一次运行中可用。
- name: Create GitHub Release and Upload Assets
uses: softprops/action-gh-release@v3
with:
- generate_release_notes: true
name: "Release ${{ github.ref_name }}"
- body: |
- Release created by CI for tag ${{ github.ref_name }}
- Package version: ${{ needs.build-pack.outputs.package_version }}
+ body: ${{ steps.cliff_release.outputs.content }}
draft: false
prerelease: false
files: |
./packages/*.nupkg
env:
GITHUB_TOKEN: ${{ github.token }}
+
+ - name: Write publish summary
+ env:
+ CLIFF_RELEASE_NOTES: ${{ steps.cliff_release.outputs.content }}
+ run: |
+ {
+ echo "## GitHub Release"
+ echo
+ echo "- Tag: \`${{ github.ref_name }}\`"
+ echo "- Package version: \`${{ needs.build-pack.outputs.package_version }}\`"
+ echo
+ printf '%s\n' "${CLIFF_RELEASE_NOTES}"
+ } >> "${GITHUB_STEP_SUMMARY}"