Merge pull request #320 from doudou0720/beta-image
!refactor(CI/CD):构建工作流重构
This commit is contained in:
@@ -1,35 +1,399 @@
|
|||||||
name: .NET Build
|
name: .NET Build & PR Check
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ main,beta ]
|
branches: [ main, beta ]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
paths-ignore:
|
||||||
|
- '**/*.md'
|
||||||
|
- 'docs/**'
|
||||||
|
- 'Images/**'
|
||||||
|
- 'Manual.md'
|
||||||
|
- 'README.md'
|
||||||
|
- 'UpdateLog.md'
|
||||||
|
- 'CODE_OF_CONDUCT.md'
|
||||||
|
- 'LICENSE'
|
||||||
|
- 'privacy.txt'
|
||||||
|
- 'icc.png'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}-${{ github.head_ref || github.sha }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
find-or-create-pr-comment:
|
||||||
build:
|
name: Find or Create PR Comment
|
||||||
runs-on: windows-latest
|
if: github.event_name == 'pull_request'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
outputs:
|
||||||
|
comment_id: ${{ steps.find-comment.outputs.comment_id }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.2.2
|
- name: Find existing bot comment
|
||||||
|
id: find-comment
|
||||||
|
run: |
|
||||||
|
# 查找包含特定标记的现有评论
|
||||||
|
COMMENTS=$(gh api \
|
||||||
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
|
"/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \
|
||||||
|
--jq '.[] | select(.body | contains("<!-- github-action-pr-build -->")) | .id' | head -1)
|
||||||
|
|
||||||
|
if [ -n "$COMMENTS" ]; then
|
||||||
|
echo "📝 找到现有评论 ID: $COMMENTS"
|
||||||
|
echo "comment_id=$COMMENTS" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "📝 未找到现有评论,将创建新评论"
|
||||||
|
echo "comment_id=" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
- name: Setup MSbuild
|
pr-preview-comment:
|
||||||
uses: microsoft/setup-msbuild@v2
|
name: PR Preview (Building)
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
- name: Setup NuGet
|
runs-on: ubuntu-latest
|
||||||
uses: NuGet/setup-nuget@v2.0.1
|
needs: find-or-create-pr-comment
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
outputs:
|
||||||
|
comment_id: ${{ steps.create-preview-comment.outputs.comment-id }}
|
||||||
|
steps:
|
||||||
|
- name: Prepare Preview Comment
|
||||||
|
id: prepare-preview
|
||||||
|
env:
|
||||||
|
GH_REPO: ${{ github.repository }}
|
||||||
|
GH_RUN_ID: ${{ github.run_id }}
|
||||||
|
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||||
|
IS_READY_FOR_REVIEW: ${{ github.event.action == 'ready_for_review' }}
|
||||||
|
run: |
|
||||||
|
# 构建预览评论内容
|
||||||
|
{
|
||||||
|
if [ "$IS_READY_FOR_REVIEW" = "true" ]; then
|
||||||
|
echo "# 🚀 PR 准备审查 - 构建预览"
|
||||||
|
echo ""
|
||||||
|
echo "**状态:** 🟡 正在构建(准备审查状态)..."
|
||||||
|
else
|
||||||
|
echo "# 🏗️ PR 构建预览"
|
||||||
|
echo ""
|
||||||
|
echo "**状态:** 🟡 正在构建..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "**分支提交:** \`$PR_HEAD_SHA\`"
|
||||||
|
echo "**操作:** [查看运行详情](https://github.com/$GH_REPO/actions/runs/$GH_RUN_ID)"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ "$IS_READY_FOR_REVIEW" = "true" ]; then
|
||||||
|
echo "> 📋 此 PR 已标记为 **准备审查**,正在进行构建验证"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "---"
|
||||||
|
echo "<!-- github-action-pr-build -->"
|
||||||
|
echo "<!-- build-id: $GH_RUN_ID -->"
|
||||||
|
echo "<!-- event-type: ${{ github.event.action }} -->"
|
||||||
|
echo "<!-- pr-head-sha: $PR_HEAD_SHA -->"
|
||||||
|
echo "<!-- merge-sha: ${{ github.sha }} -->"
|
||||||
|
echo ""
|
||||||
|
echo "🤖 构建完成后,状态将自动更新"
|
||||||
|
} > preview_comment.txt
|
||||||
|
|
||||||
|
preview_content=$(cat preview_comment.txt)
|
||||||
|
echo "preview_body<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
echo "$preview_content" >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Restore NuGet Packages
|
- name: Post/Update Preview Comment
|
||||||
run: nuget restore "Ink Canvas.sln"
|
id: create-preview-comment
|
||||||
|
uses: peter-evans/create-or-update-comment@v4
|
||||||
|
with:
|
||||||
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
|
comment-id: ${{ needs.find-or-create-pr-comment.outputs.comment_id }}
|
||||||
|
body: ${{ steps.prepare-preview.outputs.preview_body }}
|
||||||
|
edit-mode: replace
|
||||||
|
|
||||||
- name: Build the Solution
|
build-and-package:
|
||||||
run: |
|
name: Build & Package
|
||||||
msbuild -t:restore /p:GitFlow="Github Action"
|
runs-on: windows-latest
|
||||||
msbuild /p:platform="AnyCPU" /p:configuration="Debug" /p:GitFlow="Github Action" "Ink Canvas/InkCanvasForClass.csproj"
|
outputs:
|
||||||
|
archive_name: ${{ steps.create-archive.outputs.archive_name }}
|
||||||
|
build_result: ${{ steps.check-exe.outputs.build_success }}
|
||||||
|
artifact_url: ${{ steps.upload-artifact.outputs.artifact-url }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
|
||||||
- name: Upload to artifact
|
- name: Setup NuGet
|
||||||
uses: actions/upload-artifact@v4.5.0
|
uses: NuGet/setup-nuget@v2.0.1
|
||||||
with:
|
|
||||||
name: InkCanvasForClass
|
- name: Setup MSBuild
|
||||||
path: "Ink Canvas/bin/Debug/net472"
|
uses: microsoft/setup-msbuild@v2
|
||||||
|
|
||||||
|
- name: Cache NuGet global packages
|
||||||
|
id: cache-nuget
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
# NuGet 全局包缓存(已下载的包)
|
||||||
|
~/.nuget/packages
|
||||||
|
# NuGet 缓存目录(包索引)
|
||||||
|
~\AppData\Local\NuGet\Cache
|
||||||
|
key: ${{ runner.os }}-nuget-v2-${{ hashFiles('**/*.csproj', '**/packages.config', '**/*.sln', '**/nuget.config') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-nuget-v2-
|
||||||
|
|
||||||
|
- name: Cache obj/ folders
|
||||||
|
id: cache-obj
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
# MSBuild 生成的 obj/ 文件夹
|
||||||
|
Ink Canvas/obj
|
||||||
|
key: ${{ runner.os }}-obj-v2-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-obj-v2-
|
||||||
|
|
||||||
|
- name: "Cache debug: show cache hit status"
|
||||||
|
run: |
|
||||||
|
echo "NuGet cache hit: ${{ steps.cache-nuget.outputs.cache-hit }}"
|
||||||
|
echo "Obj cache hit: ${{ steps.cache-obj.outputs.cache-hit }}"
|
||||||
|
|
||||||
|
# Removed caching of obj/ folders to avoid cross-version incremental build issues
|
||||||
|
# NuGet packages will still be cached; always run restore to ensure packages are present
|
||||||
|
- name: Restore NuGet packages
|
||||||
|
run: |
|
||||||
|
Write-Host "📥 正在恢复 NuGet 包(始终运行以确保依赖可用)..." -ForegroundColor Yellow
|
||||||
|
|
||||||
|
# 恢复解决方案级别的包
|
||||||
|
nuget restore "Ink Canvas.sln" -Verbosity minimal
|
||||||
|
|
||||||
|
# 恢复项目级别的包(兼容 packages.config)
|
||||||
|
msbuild -t:restore "Ink Canvas/InkCanvasForClass.csproj" /p:GitFlow="Github Action" /p:RestorePackagesConfig=true /verbosity:minimal
|
||||||
|
|
||||||
|
Write-Host "✅ NuGet 包恢复完成" -ForegroundColor Green
|
||||||
|
|
||||||
|
- name: Build the Solution
|
||||||
|
run: |
|
||||||
|
Write-Host "🔨 正在构建项目..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# 如果是 ready_for_review 事件,添加特殊标记
|
||||||
|
if ("${{ github.event.action }}" -eq "ready_for_review") {
|
||||||
|
Write-Host "🚀 PR 准备审查状态构建 - 进行完整验证" -ForegroundColor Magenta
|
||||||
|
$GITFLOW = "Github Action - Ready For Review"
|
||||||
|
} else {
|
||||||
|
$GITFLOW = "Github Action"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 执行构建
|
||||||
|
msbuild /p:platform="AnyCPU" /p:configuration="Debug" /p:GitFlow="$GITFLOW" "Ink Canvas/InkCanvasForClass.csproj" /m /p:UseMultiToolTask=true /p:EnforceProcessCountAcrossBuilds=true /verbosity:minimal
|
||||||
|
|
||||||
|
Write-Host "🏗️ 构建命令执行完成" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
- name: Check if exe file is generated
|
||||||
|
id: check-exe
|
||||||
|
run: |
|
||||||
|
Write-Host "🔍 检查是否生成可执行文件..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
$exePath = "Ink Canvas\bin\Debug\net472\InkCanvasForClass.exe"
|
||||||
|
|
||||||
|
if (Test-Path $exePath) {
|
||||||
|
Write-Host "✅ 找到可执行文件: $exePath" -ForegroundColor Green
|
||||||
|
$fileInfo = Get-Item $exePath
|
||||||
|
Write-Host " 文件大小: $($fileInfo.Length) 字节" -ForegroundColor Gray
|
||||||
|
Write-Host " 创建时间: $($fileInfo.CreationTime)" -ForegroundColor Gray
|
||||||
|
echo "build_success=true" >> $env:GITHUB_OUTPUT
|
||||||
|
} else {
|
||||||
|
Write-Host "❌ 未找到可执行文件: $exePath" -ForegroundColor Red
|
||||||
|
Write-Host " 检查目录内容:" -ForegroundColor Yellow
|
||||||
|
if (Test-Path "Ink Canvas\bin\Debug\net472\") {
|
||||||
|
Get-ChildItem "Ink Canvas\bin\Debug\net472\" -ErrorAction SilentlyContinue | ForEach-Object {
|
||||||
|
Write-Host " - $($_.Name)" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host " bin\Debug\net472 目录不存在" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
echo "build_success=false" >> $env:GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# 如果是直接触发,则抛出错误
|
||||||
|
if ("${{ github.event_name }}" -eq "workflow_dispatch") {
|
||||||
|
Write-Host "🚨 工作流手动触发 - 构建失败,抛出错误!" -ForegroundColor Red -BackgroundColor Black
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Create Package (if build succeeded)
|
||||||
|
id: create-archive
|
||||||
|
if: steps.check-exe.outputs.build_success == 'true'
|
||||||
|
env:
|
||||||
|
GITHUB_SHA: ${{ github.sha }}
|
||||||
|
GITHUB_RUN_NUMBER: ${{ github.run_number }}
|
||||||
|
run: |
|
||||||
|
# 使用合并提交的短哈希(因为构建使用的是合并后的代码)
|
||||||
|
$shortSha = $env:GITHUB_SHA.Substring(0, 7)
|
||||||
|
$version = "debug-$shortSha-$env:GITHUB_RUN_NUMBER"
|
||||||
|
$archiveName = "InkCanvasForClass.CE.$version.zip"
|
||||||
|
Write-Host "📦 正在创建归档包: $archiveName" -ForegroundColor Cyan
|
||||||
|
Write-Host " 使用合并提交哈希: $env:GITHUB_SHA" -ForegroundColor Gray
|
||||||
|
Compress-Archive -Path "Ink Canvas\bin\Debug\net472\*" -DestinationPath $archiveName -Force
|
||||||
|
echo "archive_name=$archiveName" >> $env:GITHUB_OUTPUT
|
||||||
|
Write-Host "✅ 已创建归档包: $archiveName" -ForegroundColor Green
|
||||||
|
|
||||||
|
- name: Upload Artifact (if build succeeded)
|
||||||
|
id: upload-artifact
|
||||||
|
if: steps.check-exe.outputs.build_success == 'true'
|
||||||
|
uses: actions/upload-artifact@v4.5.0
|
||||||
|
with:
|
||||||
|
name: app-package
|
||||||
|
path: "*.zip"
|
||||||
|
|
||||||
|
pr-check-comment:
|
||||||
|
name: PR Check & Comment (Final)
|
||||||
|
needs: [build-and-package, pr-preview-comment]
|
||||||
|
if: always() && github.event_name == 'pull_request'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- name: Prepare Final Comment Content
|
||||||
|
id: prepare-final-comment
|
||||||
|
run: |
|
||||||
|
# 从构建作业获取构建结果
|
||||||
|
BUILD_SUCCESS="${{ needs.build-and-package.outputs.build_result }}"
|
||||||
|
ARTIFACT_URL="${{ needs.build-and-package.outputs.artifact_url }}"
|
||||||
|
|
||||||
|
# 使用 PR 分支的实际提交哈希
|
||||||
|
PR_HEAD_SHA="${{ github.event.pull_request.head.sha }}"
|
||||||
|
|
||||||
|
# 确定构建状态
|
||||||
|
if [ "$BUILD_SUCCESS" = "true" ]; then
|
||||||
|
STATUS_ICON="✅"
|
||||||
|
STATUS_TEXT="构建成功"
|
||||||
|
COLOR="#00d26a"
|
||||||
|
else
|
||||||
|
STATUS_ICON="❌"
|
||||||
|
STATUS_TEXT="构建失败"
|
||||||
|
COLOR="#f85149"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查是否是 ready_for_review 事件
|
||||||
|
READY_FOR_REVIEW="${{ github.event.action == 'ready_for_review' }}"
|
||||||
|
|
||||||
|
# 构建最终评论内容
|
||||||
|
{
|
||||||
|
if [ "$READY_FOR_REVIEW" = "true" ]; then
|
||||||
|
echo "# 🚀 PR 准备审查 - 构建结果"
|
||||||
|
echo ""
|
||||||
|
echo "> 📋 此 PR 已标记为 **准备审查**,构建验证完成"
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
echo "# 📋 构建结果摘要"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "## 本次构建状态"
|
||||||
|
echo ""
|
||||||
|
echo "| 项目 | 结果 |"
|
||||||
|
echo "|------|------|"
|
||||||
|
echo "| 状态 | $STATUS_ICON **$STATUS_TEXT** |"
|
||||||
|
echo "| 事件类型 | \`${{ github.event.action }}\` |"
|
||||||
|
echo "| 分支提交 | \`$PR_HEAD_SHA\` |"
|
||||||
|
echo "| 工作流 | [运行 #${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) |"
|
||||||
|
|
||||||
|
# 如果有构建产物,显示下载链接
|
||||||
|
if [ "$BUILD_SUCCESS" = "true" ]; then
|
||||||
|
NIGHTLY_LINK="https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/app-package.zip"
|
||||||
|
echo ""
|
||||||
|
echo "## 构建产物"
|
||||||
|
if [ -n "$ARTIFACT_URL" ]; then
|
||||||
|
echo "- 📦 [下载构建产物]($ARTIFACT_URL)"
|
||||||
|
else
|
||||||
|
echo "- 📦 [下载构建产物](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
|
||||||
|
fi
|
||||||
|
echo "- 🌙 [直链下载 (nightly.link)]($NIGHTLY_LINK)"
|
||||||
|
|
||||||
|
if [ "$READY_FOR_REVIEW" = "true" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "## 🎉 审查建议"
|
||||||
|
echo "- ✅ 构建验证通过,代码可以正常编译"
|
||||||
|
echo "- 🔍 请进行代码审查"
|
||||||
|
echo "- 🧪 建议测试构建产物功能"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$READY_FOR_REVIEW" = "true" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "## ⚠️ 审查阻塞"
|
||||||
|
echo "- ❌ 构建失败,需要修复后才能继续审查"
|
||||||
|
echo "- 🔧 请检查构建错误并修复"
|
||||||
|
echo "- 📝 修复后重新标记为准备审查"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "---"
|
||||||
|
echo "<!-- github-action-pr-build -->"
|
||||||
|
echo "<!-- build-id: ${{ github.run_id }} -->"
|
||||||
|
echo "<!-- event-type: ${{ github.event.action }} -->"
|
||||||
|
echo "<!-- pr-head-sha: $PR_HEAD_SHA -->"
|
||||||
|
echo "<!-- merge-sha: ${{ github.sha }} -->"
|
||||||
|
echo ""
|
||||||
|
echo "<sub>🤖 GitHub Actions 自动生成 • 最后更新: $(date -u +'%Y-%m-%d %H:%M:%S UTC')</sub>"
|
||||||
|
} > final_comment.txt
|
||||||
|
|
||||||
|
# 输出多行内容
|
||||||
|
final_content=$(cat final_comment.txt)
|
||||||
|
echo "final_body<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
echo "$final_content" >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
echo "最终评论内容已生成"
|
||||||
|
|
||||||
|
- name: Update Final Comment
|
||||||
|
uses: peter-evans/create-or-update-comment@v4
|
||||||
|
with:
|
||||||
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
|
comment-id: ${{ needs.pr-preview-comment.outputs.comment_id }}
|
||||||
|
body: ${{ steps.prepare-final-comment.outputs.final_body }}
|
||||||
|
edit-mode: replace
|
||||||
|
|
||||||
|
final-check:
|
||||||
|
name: Final Check (Manual Trigger)
|
||||||
|
if: always() && github.event_name == 'workflow_dispatch'
|
||||||
|
needs: [build-and-package]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check Build Result
|
||||||
|
id: check-build
|
||||||
|
run: |
|
||||||
|
BUILD_SUCCESS="${{ needs.build-and-package.outputs.build_result }}"
|
||||||
|
|
||||||
|
if [ "$BUILD_SUCCESS" = "true" ]; then
|
||||||
|
echo "✅ 构建成功 - 工作流完成"
|
||||||
|
echo "status=success" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "❌ 构建失败 - 抛出错误"
|
||||||
|
echo "status=failure" >> $GITHUB_OUTPUT
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Create Summary (if successful)
|
||||||
|
if: steps.check-build.outputs.status == 'success'
|
||||||
|
run: |
|
||||||
|
echo "# 🎉 手动构建完成" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**构建状态:** ✅ 成功" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**提交:** \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**运行编号:** #${{ github.run_number }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "[📦 下载构建产物](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**直链下载 (nightly.link):**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "[🌙 nightly.link 下载链接](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/app-package.zip)" >> $GITHUB_STEP_SUMMARY
|
||||||
+538
-278
@@ -1,6 +1,9 @@
|
|||||||
name: Pre-release and Changelog
|
name: Pre-release and Changelog
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version_type:
|
version_type:
|
||||||
@@ -19,293 +22,550 @@ on:
|
|||||||
default: true
|
default: true
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}-${{ github.sha }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
prerelease:
|
prepare:
|
||||||
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta'
|
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
permissions:
|
outputs:
|
||||||
contents: write
|
tag_name: ${{ steps.get_tag.outputs.tag_name }}
|
||||||
|
version: ${{ steps.get_tag.outputs.version }}
|
||||||
|
is_prerelease: ${{ steps.release_type.outputs.is_prerelease }}
|
||||||
|
changelog: ${{ steps.read_changelog.outputs.changelog }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4.2.2
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # 获取所有历史记录用于生成changelog
|
fetch-depth: 0
|
||||||
|
fetch-tags: true
|
||||||
- name: Setup MSbuild
|
|
||||||
uses: microsoft/setup-msbuild@v2
|
# ========== 获取当前版本 ==========
|
||||||
|
- name: Get current version from Git tag
|
||||||
- name: Setup NuGet
|
id: get_version
|
||||||
uses: NuGet/setup-nuget@v2.0.1
|
run: |
|
||||||
|
# 获取最新的tag
|
||||||
- name: Restore NuGet Packages
|
$latestTag = git describe --tags --abbrev=0 2>$null
|
||||||
run: nuget restore "Ink Canvas.sln"
|
if ($latestTag) {
|
||||||
|
# 移除v/b前缀
|
||||||
- name: Get current version from Git tag
|
$version = $latestTag -replace "^[vb]", ""
|
||||||
id: get_version
|
echo "Found latest tag: $latestTag"
|
||||||
run: |
|
} else {
|
||||||
# 获取最新的tag
|
# 如果没有tag,使用默认值
|
||||||
$latestTag = git describe --tags --abbrev=0 2>$null
|
$version = "1.0.0.0"
|
||||||
if ($latestTag) {
|
echo "No tag found, using default version: $version"
|
||||||
# 移除v前缀(如果有的话)
|
|
||||||
$version = $latestTag -replace "^v", ""
|
|
||||||
echo "Found latest tag: $latestTag"
|
|
||||||
} else {
|
|
||||||
# 如果没有tag,使用默认版本
|
|
||||||
$version = "1.0.0.0"
|
|
||||||
echo "No tags found, using default version"
|
|
||||||
}
|
|
||||||
echo "current_version=$version" >> $env:GITHUB_OUTPUT
|
|
||||||
echo "Current version: $version"
|
|
||||||
|
|
||||||
- name: Calculate new version
|
|
||||||
id: calc_version
|
|
||||||
run: |
|
|
||||||
$currentVersion = "${{ steps.get_version.outputs.current_version }}"
|
|
||||||
$versionParts = $currentVersion.Split('.')
|
|
||||||
|
|
||||||
# 确保版本号格式正确(支持4部分)
|
|
||||||
if ($versionParts.Length -ge 3) {
|
|
||||||
$major = [int]$versionParts[0]
|
|
||||||
$minor = [int]$versionParts[1]
|
|
||||||
$patch = [int]$versionParts[2]
|
|
||||||
$build = [int]$versionParts[3]
|
|
||||||
} else {
|
|
||||||
# 如果版本号格式不正确,使用默认值
|
|
||||||
$major = 1
|
|
||||||
$minor = 0
|
|
||||||
$patch = 0
|
|
||||||
$build = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
$versionType = "${{ github.event.inputs.version_type }}"
|
|
||||||
|
|
||||||
switch ($versionType) {
|
|
||||||
"major" {
|
|
||||||
$major++
|
|
||||||
$minor = 0
|
|
||||||
$patch = 0
|
|
||||||
$build = 0
|
|
||||||
}
|
}
|
||||||
"minor" {
|
echo "current_version=$version" >> $env:GITHUB_OUTPUT
|
||||||
$minor++
|
echo "Current version: $version"
|
||||||
$patch = 0
|
|
||||||
$build = 0
|
# ========== 处理版本号和标签名 ==========
|
||||||
}
|
- name: Get tag name and version
|
||||||
"patch" {
|
id: get_tag
|
||||||
$patch++
|
run: |
|
||||||
$build = 0
|
if ("${{ github.event_name }}" -eq "push") {
|
||||||
}
|
# 从 push tag 事件获取原始标签名
|
||||||
"build" {
|
$tagName = "${{ github.ref }}".Replace("refs/tags/", "")
|
||||||
$build++
|
# 移除 v/b 前缀获取纯版本号
|
||||||
}
|
$cleanVersion = $tagName -replace "^[vb]", ""
|
||||||
}
|
|
||||||
|
|
||||||
# 生成新版本号(4位格式,如1.7.18.0)
|
|
||||||
$newVersion = "$major.$minor.$patch.$build"
|
|
||||||
echo "new_version=$newVersion" >> $env:GITHUB_OUTPUT
|
|
||||||
echo "New version: $newVersion"
|
|
||||||
|
|
||||||
- name: Generate Changelog
|
|
||||||
id: changelog
|
|
||||||
run: |
|
|
||||||
# 获取上次tag到现在的所有commit
|
|
||||||
$lastTag = git describe --tags --abbrev=0 2>$null
|
|
||||||
if ($lastTag) {
|
|
||||||
$commits = git log --pretty=format:"%h|%s|%an|%ad" --date=short "$lastTag..HEAD"
|
|
||||||
} else {
|
|
||||||
$commits = git log --pretty=format:"%h|%s|%an|%ad" --date=short
|
|
||||||
}
|
|
||||||
|
|
||||||
# 初始化分类数组
|
|
||||||
$fixes = @()
|
|
||||||
$improvements = @()
|
|
||||||
$additions = @()
|
|
||||||
$deletions = @()
|
|
||||||
$versionChanges = @()
|
|
||||||
$others = @()
|
|
||||||
|
|
||||||
# 解析每个commit
|
|
||||||
foreach ($commit in $commits) {
|
|
||||||
if ($commit -match "^([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)$") {
|
|
||||||
$hash = $matches[1]
|
|
||||||
$message = $matches[2]
|
|
||||||
$author = $matches[3]
|
|
||||||
$date = $matches[4]
|
|
||||||
|
|
||||||
$commitInfo = @{
|
echo "tag_name=$tagName" >> $env:GITHUB_OUTPUT
|
||||||
Hash = $hash
|
echo "version=$cleanVersion" >> $env:GITHUB_OUTPUT
|
||||||
Message = $message
|
echo "Using pushed tag: $tagName, version: $cleanVersion"
|
||||||
Author = $author
|
} else {
|
||||||
Date = $date
|
# 从 workflow_dispatch 计算新版本(4位格式)
|
||||||
}
|
$currentVersion = "${{ steps.get_version.outputs.current_version }}"
|
||||||
|
$versionParts = $currentVersion.Split('.')
|
||||||
|
|
||||||
# 根据commit消息分类
|
# 确保版本号格式正确(至少4部分)
|
||||||
if ($message -match "^(fix|修复)") {
|
if ($versionParts.Length -ge 4) {
|
||||||
$fixes += $commitInfo
|
$major = [int]$versionParts[0]
|
||||||
} elseif ($message -match "^(improve|改进|优化)") {
|
$minor = [int]$versionParts[1]
|
||||||
$improvements += $commitInfo
|
$patch = [int]$versionParts[2]
|
||||||
} elseif ($message -match "^(add|新增|添加)") {
|
$build = [int]$versionParts[3]
|
||||||
$additions += $commitInfo
|
|
||||||
} elseif ($message -match "^(delete|删除|移除)") {
|
|
||||||
$deletions += $commitInfo
|
|
||||||
} elseif ($message -match "(版本|version|更新版本号)") {
|
|
||||||
$versionChanges += $commitInfo
|
|
||||||
} else {
|
} else {
|
||||||
$others += $commitInfo
|
# 如果版本号格式不正确,补充为4位
|
||||||
|
if ($versionParts.Length -ge 3) {
|
||||||
|
$major = [int]$versionParts[0]
|
||||||
|
$minor = [int]$versionParts[1]
|
||||||
|
$patch = [int]$versionParts[2]
|
||||||
|
$build = 0
|
||||||
|
} else {
|
||||||
|
# 如果版本号格式不正确,抛出错误
|
||||||
|
echo "Error: Invalid version format. Expected format: x.y.z.w (e.g., 1.7.18.0)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$versionType = "${{ github.event.inputs.version_type }}"
|
||||||
|
$isPrerelease = "${{ github.event.inputs.prerelease }}" -eq "true"
|
||||||
|
|
||||||
|
switch ($versionType) {
|
||||||
|
"major" {
|
||||||
|
$major++
|
||||||
|
$minor = 0
|
||||||
|
$patch = 0
|
||||||
|
$build = 0
|
||||||
|
}
|
||||||
|
"minor" {
|
||||||
|
$minor++
|
||||||
|
$patch = 0
|
||||||
|
$build = 0
|
||||||
|
}
|
||||||
|
"patch" {
|
||||||
|
$patch++
|
||||||
|
$build = 0
|
||||||
|
}
|
||||||
|
"build" {
|
||||||
|
$build++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 生成新版本号(4位格式,如1.7.18.0)
|
||||||
|
$newVersion = "$major.$minor.$patch.$build"
|
||||||
|
|
||||||
|
# 根据是否为预发布决定标签前缀
|
||||||
|
if ($isPrerelease) {
|
||||||
|
$tagName = "b$newVersion"
|
||||||
|
} else {
|
||||||
|
$tagName = "v$newVersion"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "tag_name=$tagName" >> $env:GITHUB_OUTPUT
|
||||||
|
echo "version=$newVersion" >> $env:GITHUB_OUTPUT
|
||||||
|
echo "New tag: $tagName, version: $newVersion"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
- name: Determine release type
|
||||||
# 生成changelog内容
|
id: release_type
|
||||||
$version = "${{ steps.calc_version.outputs.new_version }}"
|
run: |
|
||||||
$changelog = "# ICC CE $version 更新日志`n`n## 修复 (Fixes)"
|
if ("${{ github.event_name }}" -eq "push") {
|
||||||
|
# 根据 tag 名称前缀确定是否为预发布版本
|
||||||
if ($fixes.Count -gt 0) {
|
$tagName = "${{ steps.get_tag.outputs.tag_name }}"
|
||||||
foreach ($fix in $fixes) {
|
if ($tagName -and $tagName.StartsWith("b")) {
|
||||||
$changelog += "`n- $($fix.Message) ($($fix.Author), $($fix.Date))"
|
echo "is_prerelease=true" >> $env:GITHUB_OUTPUT
|
||||||
|
echo "This is a pre-release (beta)"
|
||||||
|
} else {
|
||||||
|
echo "is_prerelease=false" >> $env:GITHUB_OUTPUT
|
||||||
|
echo "This is a release"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# workflow_dispatch 方式
|
||||||
|
echo "is_prerelease=${{ github.event.inputs.prerelease }}" >> $env:GITHUB_OUTPUT
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$changelog += "`n- 无"
|
# ========== 使用 git-cliff 生成变更日志 ==========
|
||||||
}
|
- name: Generate changelog with git-cliff (for pushed tag)
|
||||||
|
if: github.event_name == 'push'
|
||||||
$changelog += "`n`n## 改进 (Improvements)"
|
id: git_cliff_tag
|
||||||
|
uses: orhun/git-cliff-action@v4
|
||||||
if ($improvements.Count -gt 0) {
|
with:
|
||||||
foreach ($improvement in $improvements) {
|
config: build/cliff.toml # 使用项目build目录的 cliff.toml 配置
|
||||||
$changelog += "`n- $($improvement.Message) ($($improvement.Author), $($improvement.Date))"
|
args: --latest --tag ${{ steps.get_tag.outputs.tag_name }} --output CHANGELOG.md
|
||||||
}
|
env:
|
||||||
} else {
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
$changelog += "`n- 无"
|
|
||||||
}
|
- name: Generate changelog with git-cliff (for workflow_dispatch)
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
$changelog += "`n`n## 新增功能 (New Features)"
|
id: git_cliff_unreleased
|
||||||
|
uses: orhun/git-cliff-action@v4
|
||||||
if ($additions.Count -gt 0) {
|
with:
|
||||||
foreach ($addition in $additions) {
|
config: build/cliff.toml
|
||||||
$changelog += "`n- $($addition.Message) ($($addition.Author), $($addition.Date))"
|
args: --unreleased --tag ${{ steps.get_tag.outputs.tag_name }} --output CHANGELOG.md
|
||||||
}
|
env:
|
||||||
} else {
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
$changelog += "`n- 无"
|
|
||||||
}
|
- name: Read changelog content
|
||||||
|
id: read_changelog
|
||||||
$changelog += "`n`n## 删除功能 (Removed Features)"
|
run: |
|
||||||
|
$changelogContent = Get-Content -Path CHANGELOG.md -Raw
|
||||||
if ($deletions.Count -gt 0) {
|
echo "changelog<<EOF" >> $env:GITHUB_OUTPUT
|
||||||
foreach ($deletion in $deletions) {
|
echo $changelogContent >> $env:GITHUB_OUTPUT
|
||||||
$changelog += "`n- $($deletion.Message) ($($deletion.Author), $($deletion.Date))"
|
echo "EOF" >> $env:GITHUB_OUTPUT
|
||||||
}
|
|
||||||
} else {
|
build:
|
||||||
$changelog += "`n- 无"
|
needs: prepare
|
||||||
}
|
if: success()
|
||||||
|
runs-on: windows-latest
|
||||||
$changelog += "`n`n## 版本更新 (Version Updates)"
|
outputs:
|
||||||
|
archive_name: ${{ steps.create_archive.outputs.archive_name }}
|
||||||
if ($versionChanges.Count -gt 0) {
|
zip_size: ${{ steps.calculate_size.outputs.zip_size }}
|
||||||
foreach ($versionChange in $versionChanges) {
|
zip_hash: ${{ steps.calculate_size.outputs.zip_hash }}
|
||||||
$changelog += "`n- $($versionChange.Message) ($($versionChange.Author), $($versionChange.Date))"
|
installer_size: ${{ steps.calculate_installer_size.outputs.installer_size }}
|
||||||
}
|
installer_hash: ${{ steps.calculate_installer_size.outputs.installer_hash }}
|
||||||
} else {
|
|
||||||
$changelog += "`n- 无"
|
steps:
|
||||||
}
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v6
|
||||||
$changelog += "`n`n## 其他更改 (Other Changes)"
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
if ($others.Count -gt 0) {
|
fetch-tags: true
|
||||||
foreach ($other in $others) {
|
|
||||||
$changelog += "`n- $($other.Message) ($($other.Author), $($other.Date))"
|
- name: Setup NuGet
|
||||||
}
|
uses: NuGet/setup-nuget@v2.0.1
|
||||||
} else {
|
|
||||||
$changelog += "`n- 无"
|
- name: Setup MSBuild
|
||||||
}
|
uses: microsoft/setup-msbuild@v2
|
||||||
|
|
||||||
$changelog += "`n`n---`n*此更新日志由GitHub Actions自动生成*"
|
- name: Install Inno Setup Unofficial Language Files
|
||||||
|
run: |
|
||||||
# 保存changelog到文件
|
# 创建临时目录用于下载文件
|
||||||
$changelog | Out-File -FilePath "CHANGELOG_${{ steps.calc_version.outputs.new_version }}.md" -Encoding UTF8
|
New-Item -ItemType Directory -Path "temp_lang" -Force
|
||||||
|
|
||||||
# 输出changelog内容到步骤输出
|
|
||||||
echo "changelog<<EOF" >> $env:GITHUB_OUTPUT
|
|
||||||
echo $changelog >> $env:GITHUB_OUTPUT
|
|
||||||
echo "EOF" >> $env:GITHUB_OUTPUT
|
|
||||||
|
|
||||||
echo "Changelog generated successfully"
|
|
||||||
|
|
||||||
- name: Display version info
|
|
||||||
run: |
|
|
||||||
echo "Current version: ${{ steps.get_version.outputs.current_version }}"
|
|
||||||
echo "New version: ${{ steps.calc_version.outputs.new_version }}"
|
|
||||||
echo "Note: Version will not be automatically updated in repository files"
|
|
||||||
|
|
||||||
- name: Build the Solution
|
|
||||||
run: |
|
|
||||||
msbuild -t:restore /p:GitFlow="Github Action"
|
|
||||||
msbuild /p:platform="AnyCPU" /p:configuration="Release" /p:GitFlow="Github Action" "Ink Canvas/InkCanvasForClass.csproj"
|
|
||||||
|
|
||||||
- name: Create Release Archive
|
|
||||||
run: |
|
|
||||||
$version = "${{ steps.calc_version.outputs.new_version }}"
|
|
||||||
$archiveName = "InkCanvasForClass.CE.$version.zip"
|
|
||||||
|
|
||||||
# 创建发布目录
|
|
||||||
New-Item -ItemType Directory -Path "release" -Force
|
|
||||||
|
|
||||||
# 复制发布文件
|
|
||||||
Copy-Item "Ink Canvas\bin\Release\net472\*" "release\" -Recurse -Force
|
|
||||||
|
|
||||||
# 创建压缩包
|
|
||||||
Compress-Archive -Path "release\*" -DestinationPath $archiveName -Force
|
|
||||||
|
|
||||||
echo "archive_name=$archiveName" >> $env:GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Upload Release Assets
|
|
||||||
uses: actions/upload-artifact@v4.5.0
|
|
||||||
with:
|
|
||||||
name: release-files-${{ steps.calc_version.outputs.new_version }}
|
|
||||||
path: |
|
|
||||||
InkCanvasForClass.CE.${{ steps.calc_version.outputs.new_version }}.zip
|
|
||||||
CHANGELOG_${{ steps.calc_version.outputs.new_version }}.md
|
|
||||||
|
|
||||||
- name: Prepare Release Info
|
# 下载英语英国版语言文件
|
||||||
run: |
|
Invoke-WebRequest -Uri "https://github.com/jrsoftware/issrc/raw/refs/heads/main/Files/Languages/Unofficial/EnglishBritish.isl" -OutFile "temp_lang\EnglishBritish.isl"
|
||||||
$version = "${{ steps.calc_version.outputs.new_version }}"
|
|
||||||
echo "Preparing release for version: $version"
|
# 下载简体中文版语言文件
|
||||||
|
Invoke-WebRequest -Uri "https://github.com/jrsoftware/issrc/raw/refs/heads/main/Files/Languages/Unofficial/ChineseSimplified.isl" -OutFile "temp_lang\ChineseSimplified.isl"
|
||||||
- name: Create GitHub Release
|
|
||||||
uses: softprops/action-gh-release@v1
|
# 将文件移动到 Inno Setup 的语言目录
|
||||||
with:
|
Move-Item -Path "temp_lang\EnglishBritish.isl" -Destination "C:\Program Files (x86)\Inno Setup 6\Languages\EnglishBritish.isl" -Force
|
||||||
tag_name: ${{ steps.calc_version.outputs.new_version }}
|
Move-Item -Path "temp_lang\ChineseSimplified.isl" -Destination "C:\Program Files (x86)\Inno Setup 6\Languages\ChineseSimplified.isl" -Force
|
||||||
name: ICC CE ${{ steps.calc_version.outputs.new_version }}
|
|
||||||
body: |
|
# 清理临时目录
|
||||||
${{ steps.changelog.outputs.changelog }}
|
Remove-Item -Path "temp_lang" -Recurse -Force
|
||||||
draft: false
|
|
||||||
prerelease: ${{ github.event.inputs.prerelease }}
|
Write-Host "✅ Inno Setup unofficial language files installed successfully" -ForegroundColor Green
|
||||||
files: |
|
|
||||||
InkCanvasForClass.CE.${{ steps.calc_version.outputs.new_version }}.zip
|
- name: Cache NuGet packages and obj files
|
||||||
env:
|
id: cache-nuget
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
- name: Generate UpdateLog preview
|
path: |
|
||||||
run: |
|
# NuGet 全局包缓存(已下载的包)
|
||||||
$version = "${{ steps.calc_version.outputs.new_version }}"
|
~/.nuget/packages
|
||||||
$changelogFile = "CHANGELOG_$version.md"
|
# NuGet 缓存目录(包索引)
|
||||||
|
~\AppData\Local\NuGet\Cache
|
||||||
# 读取生成的changelog
|
# 项目 obj 目录(包含 project.assets.json)
|
||||||
$changelogContent = Get-Content $changelogFile -Raw
|
Ink Canvas/obj/
|
||||||
|
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/packages.config', '**/*.sln') }}
|
||||||
# 生成预览内容
|
restore-keys: |
|
||||||
$previewContent = "ICC CE $version 更新日志`n" + $changelogContent
|
${{ runner.os }}-nuget-
|
||||||
|
|
||||||
echo "UpdateLog preview generated (not written to file):"
|
- name: Restore NuGet packages (if cache missed)
|
||||||
echo $previewContent
|
if: steps.cache-nuget.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
- name: Display Summary
|
Write-Host "📥 缓存未命中,正在恢复 NuGet 包..." -ForegroundColor Yellow
|
||||||
run: |
|
|
||||||
echo "=== Release Summary ==="
|
# 恢复解决方案级别的包
|
||||||
echo "Version: ${{ steps.calc_version.outputs.new_version }}"
|
nuget restore "Ink Canvas.sln" -Verbosity minimal
|
||||||
echo "Pre-release: ${{ github.event.inputs.prerelease }}"
|
|
||||||
echo "Changelog: Generated and attached to release"
|
# 恢复项目级别的包
|
||||||
echo "Archive: ICC_CE_${{ steps.calc_version.outputs.new_version }}.zip"
|
msbuild -t:restore "Ink Canvas/InkCanvasForClass.csproj" /p:GitFlow="Github Action" /p:RestorePackagesConfig=true /verbosity:minimal
|
||||||
echo ""
|
|
||||||
echo "Note: No repository files were modified"
|
Write-Host "✅ NuGet 包恢复完成" -ForegroundColor Green
|
||||||
echo "You can manually update version numbers and changelog as needed"
|
|
||||||
|
- name: Display version info
|
||||||
|
run: |
|
||||||
|
echo "Building version: ${{ needs.prepare.outputs.version }}"
|
||||||
|
echo "Tag: ${{ needs.prepare.outputs.tag_name }}"
|
||||||
|
echo "Release type: ${{ needs.prepare.outputs.is_prerelease == 'true' && 'Pre-release' || 'Release' }}"
|
||||||
|
|
||||||
|
- name: Build the Solution
|
||||||
|
run: |
|
||||||
|
Write-Host "🔨 正在构建项目..." -ForegroundColor Cyan
|
||||||
|
msbuild /p:platform="AnyCPU" /p:configuration="Release" /p:GitFlow="Github Action" "Ink Canvas/InkCanvasForClass.csproj" /m /p:UseMultiToolTask=true /p:EnforceProcessCountAcrossBuilds=true /verbosity:minimal
|
||||||
|
|
||||||
|
Write-Host "🏗️ 构建命令执行完成" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
- name: Create Release Archive
|
||||||
|
id: create_archive
|
||||||
|
run: |
|
||||||
|
$version = "${{ needs.prepare.outputs.version }}"
|
||||||
|
$archiveName = "InkCanvasForClass.CE.$version.zip"
|
||||||
|
|
||||||
|
# 创建发布目录
|
||||||
|
New-Item -ItemType Directory -Path "release" -Force
|
||||||
|
|
||||||
|
# 复制发布文件
|
||||||
|
Copy-Item "Ink Canvas\bin\Release\net472\*" "release\" -Recurse -Force
|
||||||
|
|
||||||
|
# 创建压缩包
|
||||||
|
Compress-Archive -Path "release\*" -DestinationPath $archiveName -Force
|
||||||
|
|
||||||
|
echo "archive_name=$archiveName" >> $env:GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Prepare Inno Setup script
|
||||||
|
run: |
|
||||||
|
$version = "${{ needs.prepare.outputs.version }}"
|
||||||
|
|
||||||
|
# 更新 ISS 文件中的版本信息
|
||||||
|
$issPath = "build\InkCanvasForClass CE.iss"
|
||||||
|
$issContent = Get-Content -Path $issPath -Raw
|
||||||
|
|
||||||
|
# 替换版本信息
|
||||||
|
$issContent = $issContent -replace '#define MyAppVersion ".*"', "#define MyAppVersion `"$version`""
|
||||||
|
|
||||||
|
# 替换源文件路径为相对路径(考虑到ISS文件在build目录下,需要返回上级目录)
|
||||||
|
$issContent = $issContent -replace 'Source: ".*\\{#MyAppExeName}";', 'Source: "..\release\{#MyAppExeName}";'
|
||||||
|
$issContent = $issContent -replace 'Source: ".*\\InkCanvasForClass.exe.config";', 'Source: "..\release\InkCanvasForClass.exe.config";'
|
||||||
|
|
||||||
|
# 更新输出目录为当前目录
|
||||||
|
$issContent = $issContent -replace 'OutputDir=.*', 'OutputDir=.'
|
||||||
|
|
||||||
|
# 更新默认安装目录
|
||||||
|
$issContent = $issContent -replace 'DefaultDirName=.*', 'DefaultDirName={autopf}\{#MyAppName}'
|
||||||
|
|
||||||
|
# 更新许可证文件路径为相对路径(考虑到ISS文件在build目录下,需要返回上级目录)
|
||||||
|
$issContent = $issContent -replace 'LicenseFile=.*', 'LicenseFile=..\LICENSE'
|
||||||
|
|
||||||
|
# 保存修改后的 ISS 文件
|
||||||
|
$issContent | Set-Content -Path $issPath -Encoding UTF8
|
||||||
|
|
||||||
|
# 显示修改后的 ISS 文件内容
|
||||||
|
Write-Host "Modified ISS file content:"
|
||||||
|
Write-Host $issContent
|
||||||
|
|
||||||
|
- name: Build MSI installer with Inno Setup
|
||||||
|
uses: Minionguyjpro/Inno-Setup-Action@v1.2.2
|
||||||
|
with:
|
||||||
|
path: build\InkCanvasForClass CE.iss
|
||||||
|
options: /O.
|
||||||
|
|
||||||
|
- name: Rename installer file
|
||||||
|
run: |
|
||||||
|
$version = "${{ needs.prepare.outputs.version }}"
|
||||||
|
$setupFile = "InkCanvasForClass CE Setup.exe"
|
||||||
|
$newSetupName = "InkCanvasForClass.CE.$version.Setup.exe"
|
||||||
|
|
||||||
|
if (Test-Path $setupFile) {
|
||||||
|
Rename-Item -Path $setupFile -NewName $newSetupName
|
||||||
|
Write-Host "Renamed setup file to: $newSetupName"
|
||||||
|
} else {
|
||||||
|
Write-Host "Setup file not found: $setupFile"
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Calculate archive size and hash
|
||||||
|
id: calculate_size
|
||||||
|
run: |
|
||||||
|
$version = "${{ needs.prepare.outputs.version }}"
|
||||||
|
$archiveName = "InkCanvasForClass.CE.$version.zip"
|
||||||
|
|
||||||
|
# 获取文件大小(字节)
|
||||||
|
$fileSize = (Get-Item $archiveName).Length
|
||||||
|
|
||||||
|
# 计算SHA256哈希
|
||||||
|
$hash = (Get-FileHash $archiveName -Algorithm SHA256).Hash
|
||||||
|
|
||||||
|
echo "zip_size=$fileSize" >> $env:GITHUB_OUTPUT
|
||||||
|
echo "zip_hash=$hash" >> $env:GITHUB_OUTPUT
|
||||||
|
|
||||||
|
echo "Archive size: $fileSize bytes"
|
||||||
|
echo "SHA256 hash: $hash"
|
||||||
|
|
||||||
|
- name: Calculate installer size and hash
|
||||||
|
id: calculate_installer_size
|
||||||
|
run: |
|
||||||
|
$version = "${{ needs.prepare.outputs.version }}"
|
||||||
|
$installerName = "InkCanvasForClass.CE.$version.Setup.exe"
|
||||||
|
|
||||||
|
if (Test-Path $installerName) {
|
||||||
|
# 获取文件大小(字节)
|
||||||
|
$fileSize = (Get-Item $installerName).Length
|
||||||
|
|
||||||
|
# 计算SHA256哈希
|
||||||
|
$hash = (Get-FileHash $installerName -Algorithm SHA256).Hash
|
||||||
|
|
||||||
|
echo "installer_size=$fileSize" >> $env:GITHUB_OUTPUT
|
||||||
|
echo "installer_hash=$hash" >> $env:GITHUB_OUTPUT
|
||||||
|
|
||||||
|
echo "Installer size: $fileSize bytes"
|
||||||
|
echo "SHA256 hash: $hash"
|
||||||
|
} else {
|
||||||
|
echo "Installer file not found: $installerName"
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Upload Build Artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: build-files-${{ needs.prepare.outputs.version }}
|
||||||
|
path: |
|
||||||
|
InkCanvasForClass.CE.${{ needs.prepare.outputs.version }}.zip
|
||||||
|
InkCanvasForClass.CE.${{ needs.prepare.outputs.version }}.Setup.exe
|
||||||
|
|
||||||
|
sign:
|
||||||
|
needs: [prepare, build]
|
||||||
|
if: success()
|
||||||
|
runs-on: ubuntu-latest # 改为 Ubuntu 以使用 Python 签名工具
|
||||||
|
outputs:
|
||||||
|
signatures_created: ${{ steps.sign_artifacts.outputs.signatures_created }}
|
||||||
|
zip_sigstore_file: "InkCanvasForClass.CE.${{ needs.prepare.outputs.version }}.zip.sigstore.json"
|
||||||
|
installer_sigstore_file: "InkCanvasForClass.CE.${{ needs.prepare.outputs.version }}.Setup.exe.sigstore.json"
|
||||||
|
zip_sigstore_hash: ${{ steps.calculate_zip_sig_hash.outputs.sigstore_hash }}
|
||||||
|
installer_sigstore_hash: ${{ steps.calculate_installer_sig_hash.outputs.sigstore_hash }}
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write # 需要这个权限来验证签名
|
||||||
|
steps:
|
||||||
|
- name: Download Build Artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: build-files-${{ needs.prepare.outputs.version }}
|
||||||
|
|
||||||
|
- name: Setup Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.10'
|
||||||
|
|
||||||
|
- name: Sign release artifacts with sigstore-python
|
||||||
|
id: sign_artifacts
|
||||||
|
uses: sigstore/gh-action-sigstore-python@v3.2.0
|
||||||
|
with:
|
||||||
|
inputs: |
|
||||||
|
InkCanvasForClass.CE.${{ needs.prepare.outputs.version }}.zip
|
||||||
|
InkCanvasForClass.CE.${{ needs.prepare.outputs.version }}.Setup.exe
|
||||||
|
release-signing-artifacts: true
|
||||||
|
upload-signing-artifacts: true
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Check generated signature files
|
||||||
|
run: |
|
||||||
|
version="${{ needs.prepare.outputs.version }}"
|
||||||
|
echo "Checking for generated signature files..."
|
||||||
|
ls -la *.sig* || true
|
||||||
|
echo "Current directory contents:"
|
||||||
|
pwd
|
||||||
|
ls -la
|
||||||
|
|
||||||
|
- name: Calculate ZIP signature hash
|
||||||
|
id: calculate_zip_sig_hash
|
||||||
|
run: |
|
||||||
|
version="${{ needs.prepare.outputs.version }}"
|
||||||
|
sigstoreFile="InkCanvasForClass.CE.$version.zip.sigstore.json"
|
||||||
|
|
||||||
|
if [ -f "$sigstoreFile" ]; then
|
||||||
|
# 计算SHA256哈希
|
||||||
|
sigstoreHash=$(sha256sum "$sigstoreFile" | cut -d' ' -f1)
|
||||||
|
|
||||||
|
echo "sigstore_hash=$sigstoreHash" >> $GITHUB_OUTPUT
|
||||||
|
echo "Sigstore JSON file hash: $sigstoreHash"
|
||||||
|
echo "Sigstore file size: $(stat -c%s "$sigstoreFile") bytes"
|
||||||
|
else
|
||||||
|
echo "Warning: Sigstore file not found: $sigstoreFile"
|
||||||
|
echo "sigstore_hash=" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Calculate Installer signature hash
|
||||||
|
id: calculate_installer_sig_hash
|
||||||
|
run: |
|
||||||
|
version="${{ needs.prepare.outputs.version }}"
|
||||||
|
sigstoreFile="InkCanvasForClass.CE.$version.Setup.exe.sigstore.json"
|
||||||
|
|
||||||
|
if [ -f "$sigstoreFile" ]; then
|
||||||
|
# 计算SHA256哈希
|
||||||
|
sigstoreHash=$(sha256sum "$sigstoreFile" | cut -d' ' -f1)
|
||||||
|
|
||||||
|
echo "sigstore_hash=$sigstoreHash" >> $GITHUB_OUTPUT
|
||||||
|
echo "Sigstore JSON file hash: $sigstoreHash"
|
||||||
|
echo "Sigstore file size: $(stat -c%s "$sigstoreFile") bytes"
|
||||||
|
else
|
||||||
|
echo "Warning: Sigstore file not found: $sigstoreFile"
|
||||||
|
echo "sigstore_hash=" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload Signed Artifacts
|
||||||
|
if: steps.calculate_zip_sig_hash.outputs.sigstore_hash != '' || steps.calculate_installer_sig_hash.outputs.sigstore_hash != ''
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: signed-files-${{ needs.prepare.outputs.version }}
|
||||||
|
path: |
|
||||||
|
InkCanvasForClass.CE.${{ needs.prepare.outputs.version }}.zip.sigstore.json
|
||||||
|
InkCanvasForClass.CE.${{ needs.prepare.outputs.version }}.Setup.exe.sigstore.json
|
||||||
|
|
||||||
|
release:
|
||||||
|
needs: [prepare, build, sign]
|
||||||
|
if: success()
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Download Build Artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: build-files-${{ needs.prepare.outputs.version }}
|
||||||
|
|
||||||
|
- name: Download Signed Artifacts (if exists)
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: signed-files-${{ needs.prepare.outputs.version }}
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
|
||||||
|
- name: Create enhanced changelog with file table
|
||||||
|
id: enhanced_changelog
|
||||||
|
run: |
|
||||||
|
version="${{ needs.prepare.outputs.version }}"
|
||||||
|
|
||||||
|
# 读取git-cliff生成的changelog内容
|
||||||
|
originalChangelog="${{ needs.prepare.outputs.changelog }}"
|
||||||
|
|
||||||
|
# 构建文件信息表格
|
||||||
|
fileTable=$'\n## 文件信息 (File Information)\n'
|
||||||
|
fileTable+=$'| 文件名 | 大小 | SHA256 哈希 |\n'
|
||||||
|
fileTable+=$'|--------|------|-------------|\n'
|
||||||
|
|
||||||
|
# ZIP 文件信息
|
||||||
|
fileTable+=$'| InkCanvasForClass.CE.'"$version"
|
||||||
|
fileTable+=$'.zip | ${{ needs.build.outputs.zip_size }} bytes | ${{ needs.build.outputs.zip_hash }} |\n'
|
||||||
|
|
||||||
|
# 安装包文件信息
|
||||||
|
installerSize="${{ needs.build.outputs.installer_size }}"
|
||||||
|
installerHash="${{ needs.build.outputs.installer_hash }}"
|
||||||
|
if [ -n "$installerSize" ] && [ -n "$installerHash" ]; then
|
||||||
|
fileTable+=$'| InkCanvasForClass.CE.'"$version"'.Setup.exe | '"$installerSize"' bytes | '"$installerHash"
|
||||||
|
fileTable+=$' |\n'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查是否有签名文件
|
||||||
|
if [ -f "InkCanvasForClass.CE.$version.zip.sigstore.json" ]; then
|
||||||
|
sigstoreSize=$(stat -c%s "InkCanvasForClass.CE.$version.zip.sigstore.json")
|
||||||
|
sigstoreHash=$(sha256sum "InkCanvasForClass.CE.$version.zip.sigstore.json" | cut -d' ' -f1)
|
||||||
|
fileTable+=$'| InkCanvasForClass.CE.'"$version"'.zip.sigstore.json | '"$sigstoreSize"' bytes | '"$sigstoreHash"
|
||||||
|
fileTable+=$' |\n'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查安装程序签名文件
|
||||||
|
if [ -f "InkCanvasForClass.CE.$version.Setup.exe.sigstore.json" ]; then
|
||||||
|
sigstoreSize=$(stat -c%s "InkCanvasForClass.CE.$version.Setup.exe.sigstore.json")
|
||||||
|
sigstoreHash=$(sha256sum "InkCanvasForClass.CE.$version.Setup.exe.sigstore.json" | cut -d' ' -f1)
|
||||||
|
fileTable+=$'| InkCanvasForClass.CE.'"$version"'.Setup.exe.sigstore.json | '"$sigstoreSize"' bytes | '"$sigstoreHash"
|
||||||
|
fileTable+=$' |\n'
|
||||||
|
fi
|
||||||
|
|
||||||
|
fileTable+=$'\n*文件哈希和大小信息由GitHub Actions自动生成*\n'
|
||||||
|
|
||||||
|
# 将表格附加到原始changelog
|
||||||
|
enhancedChangelog="${originalChangelog}${fileTable}"
|
||||||
|
|
||||||
|
# 输出增强版changelog内容
|
||||||
|
echo "enhanced_changelog<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
echo "$enhancedChangelog" >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
echo "Enhanced changelog created with file information table"
|
||||||
|
|
||||||
|
- name: Display Release Info
|
||||||
|
run: |
|
||||||
|
echo "=== Creating Release ==="
|
||||||
|
echo "Version: ${{ needs.prepare.outputs.version }}"
|
||||||
|
echo "Tag: ${{ needs.prepare.outputs.tag_name }}"
|
||||||
|
echo "Pre-release: ${{ needs.prepare.outputs.is_prerelease }}"
|
||||||
|
|
||||||
|
- name: Create GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
tag_name: ${{ needs.prepare.outputs.tag_name }}
|
||||||
|
name: ICC CE ${{ needs.prepare.outputs.version }}
|
||||||
|
body: |
|
||||||
|
${{ steps.enhanced_changelog.outputs.enhanced_changelog }}
|
||||||
|
draft: false
|
||||||
|
prerelease: ${{ needs.prepare.outputs.is_prerelease == 'true' }}
|
||||||
|
files: |
|
||||||
|
InkCanvasForClass.CE.${{ needs.prepare.outputs.version }}.zip
|
||||||
|
InkCanvasForClass.CE.${{ needs.prepare.outputs.version }}.Setup.exe
|
||||||
|
InkCanvasForClass.CE.${{ needs.prepare.outputs.version }}.zip.sigstore.json
|
||||||
|
InkCanvasForClass.CE.${{ needs.prepare.outputs.version }}.Setup.exe.sigstore.json
|
||||||
|
fail_on_unmatched_files: false
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
; 脚本由 Inno Setup 脚本向导生成。
|
||||||
|
; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
|
||||||
|
|
||||||
|
#define MyAppName "InkCanvasForClass CE"
|
||||||
|
#define MyAppVersion "1.7.18.1"
|
||||||
|
#define MyAppPublisher "CJK_mkp"
|
||||||
|
#define MyAppURL "https://inkcanvasforclass.github.io"
|
||||||
|
#define MyAppExeName "InkCanvasForClass.exe"
|
||||||
|
#define MyAppAssocName MyAppName + ""
|
||||||
|
#define MyAppAssocExt ".exe"
|
||||||
|
#define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt
|
||||||
|
|
||||||
|
[Setup]
|
||||||
|
; 注意:AppId 的值唯一标识此应用程序。不要在其他应用程序的安装程序中使用相同的 AppId 值。
|
||||||
|
; (若要生成新的 GUID,请在 IDE 中单击 "工具|生成 GUID"。)
|
||||||
|
AppId={{CA801226-FD02-4C78-BCF8-753B38E70CB3}}
|
||||||
|
AppName={#MyAppName}
|
||||||
|
AppVersion={#MyAppVersion}
|
||||||
|
;AppVerName={#MyAppName} {#MyAppVersion}
|
||||||
|
AppPublisher={#MyAppPublisher}
|
||||||
|
AppPublisherURL={#MyAppURL}
|
||||||
|
AppSupportURL={#MyAppURL}
|
||||||
|
AppUpdatesURL={#MyAppURL}
|
||||||
|
DefaultDirName={autopf}\{#MyAppName}
|
||||||
|
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||||
|
ChangesAssociations=yes
|
||||||
|
DefaultGroupName={#MyAppName}
|
||||||
|
AllowNoIcons=yes
|
||||||
|
LicenseFile=LICENSE
|
||||||
|
; 取消注释以下行以在非管理员安装模式下运行 (仅为当前用户安装)。
|
||||||
|
;PrivilegesRequired=lowest
|
||||||
|
PrivilegesRequiredOverridesAllowed=dialog
|
||||||
|
OutputDir=.
|
||||||
|
OutputBaseFilename=InkCanvasForClass CE Setup
|
||||||
|
SolidCompression=yes
|
||||||
|
WizardStyle=modern
|
||||||
|
|
||||||
|
[Languages]
|
||||||
|
Name: "chinesesimp"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
|
||||||
|
Name: "english"; MessagesFile: "compiler:Languages\EnglishBritish.isl"
|
||||||
|
|
||||||
|
[Tasks]
|
||||||
|
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||||
|
|
||||||
|
[Files]
|
||||||
|
Source: "release\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
Source: "release\InkCanvasForClass.exe.config"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
; 注意:不要在任何共享系统文件上使用 "Flags: ignoreversion"
|
||||||
|
|
||||||
|
[Registry]
|
||||||
|
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocExt}\OpenWithProgids"; ValueType: string; ValueName: "{#MyAppAssocKey}"; ValueData: ""; Flags: uninsdeletevalue
|
||||||
|
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}"; ValueType: string; ValueName: ""; ValueData: "{#MyAppAssocName}"; Flags: uninsdeletekey
|
||||||
|
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"
|
||||||
|
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""
|
||||||
|
|
||||||
|
[Icons]
|
||||||
|
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||||
|
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}"
|
||||||
|
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
|
||||||
|
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
||||||
|
|
||||||
|
[Run]
|
||||||
|
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# git-cliff ~ configuration file
|
||||||
|
# https://git-cliff.org/docs/configuration
|
||||||
|
|
||||||
|
|
||||||
|
[changelog]
|
||||||
|
# A Tera template to be rendered for each release in the changelog.
|
||||||
|
# See https://keats.github.io/tera/docs/#introduction
|
||||||
|
body = """
|
||||||
|
{% if version %}\
|
||||||
|
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||||
|
{% else %}\
|
||||||
|
## [unreleased]
|
||||||
|
{% endif %}\
|
||||||
|
{% for group, commits in commits | group_by(attribute="group") %}
|
||||||
|
### {{ group | striptags | trim | upper_first }}
|
||||||
|
{% for commit in commits %}
|
||||||
|
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
|
||||||
|
{% if commit.breaking %}[**breaking**] {% endif %}\
|
||||||
|
{{ commit.message | upper_first }} ({{commit.id}} by {{commit.author.name}})\
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
"""
|
||||||
|
# Remove leading and trailing whitespaces from the changelog's body.
|
||||||
|
trim = true
|
||||||
|
# Render body even when there are no releases to process.
|
||||||
|
render_always = true
|
||||||
|
# An array of regex based postprocessors to modify the changelog.
|
||||||
|
postprocessors = [
|
||||||
|
# Replace the placeholder <REPO> with a URL.
|
||||||
|
#{ pattern = '<REPO>', replace = "https://github.com/orhun/git-cliff" },
|
||||||
|
]
|
||||||
|
# render body even when there are no releases to process
|
||||||
|
# render_always = true
|
||||||
|
# output file path
|
||||||
|
# output = "test.md"
|
||||||
|
|
||||||
|
[git]
|
||||||
|
# Parse commits according to the conventional commits specification.
|
||||||
|
# See https://www.conventionalcommits.org
|
||||||
|
conventional_commits = true
|
||||||
|
# Exclude commits that do not match the conventional commits specification.
|
||||||
|
filter_unconventional = true
|
||||||
|
# Require all commits to be conventional.
|
||||||
|
# Takes precedence over filter_unconventional.
|
||||||
|
require_conventional = false
|
||||||
|
# Split commits on newlines, treating each line as an individual commit.
|
||||||
|
split_commits = false
|
||||||
|
# An array of regex based parsers to modify commit messages prior to further processing.
|
||||||
|
commit_preprocessors = [
|
||||||
|
# Replace issue numbers with link templates to be updated in `changelog.postprocessors`.
|
||||||
|
#{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"},
|
||||||
|
# Check spelling of the commit message using https://github.com/crate-ci/typos.
|
||||||
|
# If the spelling is incorrect, it will be fixed automatically.
|
||||||
|
#{ pattern = '.*', replace_command = 'typos --write-changes -' },
|
||||||
|
]
|
||||||
|
# Prevent commits that are breaking from being excluded by commit parsers.
|
||||||
|
protect_breaking_commits = false
|
||||||
|
# An array of regex based parsers for extracting data from the commit message.
|
||||||
|
# Assigns commits to groups.
|
||||||
|
# Optionally sets the commit's scope and can decide to exclude commits from further processing.
|
||||||
|
|
||||||
|
commit_parsers = [
|
||||||
|
{ message = "^(add|新增|添加)", group = "<!-- 0 -->🚀 新增功能" },
|
||||||
|
{ message = "^(fix|修复)", group = "<!-- 1 -->🐛 修复" },
|
||||||
|
{ message = "^doc", group = "<!-- 5 -->📚 文档更改" },
|
||||||
|
{ message = "^(improve|改进|优化)", group = "<!-- 3 -->⚡ 体验优化" },
|
||||||
|
{ message = "^refactor", group = "<!-- 2 -->🚜 重构" },
|
||||||
|
{ message = "^style", group = "<!-- 6 -->🎨 格式化" },
|
||||||
|
{ message = "^(delete|删除|移除)", group = "<!-- 4 -->❌ 删除功能" },
|
||||||
|
{ message = "^test", group = "<!-- 7 -->🧪 测试" },
|
||||||
|
{ message = "^chore\\(release\\): prepare for", skip = true },
|
||||||
|
{ message = "^chore\\(deps.*\\)", skip = true },
|
||||||
|
{ message = "^chore\\(pr\\)", skip = true },
|
||||||
|
{ message = "^chore\\(pull\\)", skip = true },
|
||||||
|
{ message = "^chore|^ci", group = "<!-- 8 -->⚙️ 杂项" },
|
||||||
|
{ body = ".*security", group = "<!-- 9 -->🛡️ 安全" },
|
||||||
|
{ message = "^revert", group = "<!-- 10 -->◀️ 回退" },
|
||||||
|
{ message = "(版本|version|更新版本号)", group = "<!-- 11 -->🎉 版本号更新" },
|
||||||
|
{ message = ".*", group = "<!-- 12 -->💼 其他更改" },
|
||||||
|
]
|
||||||
|
# Exclude commits that are not matched by any commit parser.
|
||||||
|
filter_commits = false
|
||||||
|
# An array of link parsers for extracting external references, and turning them into URLs, using regex.
|
||||||
|
link_parsers = []
|
||||||
|
# Include only the tags that belong to the current branch.
|
||||||
|
use_branch_tags = false
|
||||||
|
# Order releases topologically instead of chronologically.
|
||||||
|
topo_order = false
|
||||||
|
# Order releases topologically instead of chronologically.
|
||||||
|
topo_order_commits = true
|
||||||
|
# Order of commits in each group/release within the changelog.
|
||||||
|
# Allowed values: newest, oldest
|
||||||
|
sort_commits = "oldest"
|
||||||
|
# Process submodules commits
|
||||||
|
recurse_submodules = false
|
||||||
Reference in New Issue
Block a user