Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 132 additions & 50 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
# 发布工作流(NuGet + GitHub Release)
#
# 功能:当推送标签时自动构建、打包并发布到 NuGet.org 和 GitHub Release
# 发布工作流(NuGet + GitHub Packages + GitHub Release)
#
# 功能:当推送标签时自动构建、打包,并将相同产物并发发布到 NuGet.org 与 GitHub Packages,
# 最后创建 GitHub Release。
# 触发条件:推送任何标签(如 v1.0.0 或 1.0.0)
# 权限:允许写入内容、包和使用 OIDC 身份验证
name: Publish (NuGet + GitHub Release)
name: Publish (NuGet + GitHub Packages + GitHub Release)

# 触发:推送 tag 时触发(例如 v1.0.0 或 1.0.0)
on:
push:
tags:
- '*'

# 顶级权限:允许创建 release、写 packages,并允许 id-token(OIDC)
permissions:
contents: write
packages: write
id-token: write

jobs:
build-and-publish:
build-pack:
name: Build And Pack
runs-on: ubuntu-latest

permissions:
contents: read
packages: read
id-token: write
contents: write
packages: write

outputs:
package_version: ${{ steps.tag_version.outputs.version }}

steps:
- name: Checkout repository (at tag)
Expand All @@ -38,19 +41,17 @@ jobs:
with:
dotnet-version: 10.0.x

- name: Install unzip (for reading .nuspec from .nupkg)
run: sudo apt-get update && sudo apt-get install -y unzip
- name: Cache NuGet packages
uses: actions/cache@v5
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}

- name: Restore dependencies
run: dotnet restore

# 从 GitHub 引用中提取标签版本
# 提取逻辑:去除 refs/tags/ 前缀,然后去除 v/V 前缀
# 输出:version - 处理后的版本号

# 从 GitHub 引用中提取标签版本。
# 提取逻辑:去除 refs/tags/ 前缀,然后去除 v/V 前缀。
- name: Determine tag version
id: tag_version
run: |
Expand All @@ -60,14 +61,25 @@ jobs:
VERSION=${TAG#v}
VERSION=${VERSION#V}
echo "tag='$TAG' -> version='$VERSION'"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> "$GITHUB_OUTPUT"

- name: Pack (use tag version)
run: |
set -e
echo "Packing with version=${{ steps.tag_version.outputs.version }}"
dotnet pack -c Release -o ./packages -p:PackageVersion=${{ steps.tag_version.outputs.version }} -p:IncludeSymbols=false
# 上传许可证合规相关的工件文件,包括通知文件、第三方许可证、SBOM文件及验证结果

- name: Show packages
run: ls -la ./packages || true

# 上传 nupkg 工件,供多个发布 job 复用,避免重复打包。
- name: Upload package artifacts
uses: actions/upload-artifact@v7
with:
name: packages
path: ./packages/*.nupkg

# 上传许可证合规相关的工件文件,包括通知文件、第三方许可证、SBOM 文件及验证结果。
- name: Upload compliance artifacts
uses: actions/upload-artifact@v7
with:
Expand All @@ -79,7 +91,30 @@ jobs:
sbom.cyclonedx.json
sbom-spdx-validation.txt
sbom-cyclonedx-validation.txt
- name: Show packages

publish-nuget:
name: Publish To NuGet.org
runs-on: ubuntu-latest
needs: build-pack

permissions:
contents: read
packages: read
id-token: write

Comment thread
sourcery-ai[bot] marked this conversation as resolved.
steps:
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x

- name: Download package artifacts
uses: actions/download-artifact@v5
with:
name: packages
path: ./packages

- name: Show downloaded packages
run: ls -la ./packages || true

- name: NuGet login (OIDC → temporary API key)
Expand All @@ -88,9 +123,8 @@ jobs:
with:
user: ${{ secrets.NUGET_USER }}

# 将所有生成的包推送到 nuget.org
# 使用临时 API 密钥进行身份验证
# 跳过重复包的上传
# 将所有生成的包推送到 nuget.org。
# 使用临时 API 密钥进行身份验证,并跳过重复包上传。
- name: Push all packages to nuget.org
env:
NUGET_API_KEY: ${{ steps.nuget_login.outputs.NUGET_API_KEY }}
Expand All @@ -110,44 +144,92 @@ jobs:
if [ "$pushed_any" = false ]; then
echo "No packages found to push."
fi

# 从 .nupkg 文件中提取版本信息
# 通过解压 .nupkg(zip 格式)并读取 .nuspec 文件来获取版本
# 输出:
# package_file - 第一个找到的包文件路径
# package_basename - 包文件的基本名称
# version - 从 nuspec 中解析出的版本号
- name: Get Version and First Package Path
id: get_version

publish-github-packages:
name: Publish To GitHub Packages
runs-on: ubuntu-latest
needs: build-pack

permissions:
contents: read
packages: write

steps:
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x

- name: Download package artifacts
uses: actions/download-artifact@v5
with:
name: packages
path: ./packages

- name: Show downloaded packages
run: ls -la ./packages || true

# 使用仓库内建的 GITHUB_TOKEN 配置 GitHub Packages NuGet 源。
- name: Configure GitHub Packages source
run: |
set -e
PACKAGE_FILE=$(find ./packages -name "*.nupkg" | head -n 1 || true)
if [ -z "$PACKAGE_FILE" ]; then
echo "No .nupkg file found in ./packages"
exit 1
fi
# 从 .nupkg(zip)里读取 .nuspec 并提取 <version>
VERSION=$(unzip -p "$PACKAGE_FILE" '*.nuspec' 2>/dev/null | sed -n 's:.*<version>\(.*\)</version>.*:\1:p' | head -n1)
if [ -z "$VERSION" ]; then
echo "Failed to parse version from $PACKAGE_FILE"
exit 1
dotnet nuget add source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \
--name github \
--username "${{ github.repository_owner }}" \
--password "${{ github.token }}" \
--store-password-in-clear-text

- name: Push all packages to GitHub Packages
run: |
set -e
pushed_any=false
for PKG in ./packages/*.nupkg; do
[ -f "$PKG" ] || continue
pushed_any=true
echo "Pushing $PKG to GitHub Packages..."
dotnet nuget push "$PKG" \
--source github \
--skip-duplicate
done
if [ "$pushed_any" = false ]; then
echo "No packages found to push."
fi
BASENAME=$(basename "$PACKAGE_FILE")
echo "package_file=$PACKAGE_FILE" >> $GITHUB_OUTPUT
echo "package_basename=$BASENAME" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT

# 创建 GitHub Release
# 使用从包中提取的版本信息和当前标签创建发布
# 发布包含描述信息和版本详情

create-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs:
- build-pack
- publish-nuget
- publish-github-packages
if: ${{ always() && needs.build-pack.result == 'success' }}

permissions:
contents: write
packages: read

steps:
- name: Download package artifacts
uses: actions/download-artifact@v5
with:
name: packages
path: ./packages

- name: Download compliance artifacts
uses: actions/download-artifact@v5
with:
name: license-compliance
path: .

# 无论某一侧包源发布是否失败,都继续创建 Release,并在正文中标注结果。
- name: Create GitHub Release and Upload Assets
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
name: "Release ${{ github.ref_name }}"
body: |
Release created by CI for tag ${{ github.ref_name }}
Package version: ${{ steps.get_version.outputs.version }}
Package version: ${{ needs.build-pack.outputs.package_version }}

## Compliance
- NOTICE
Expand All @@ -164,4 +246,4 @@ jobs:
sbom-spdx-validation.txt
sbom-cyclonedx-validation.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ github.token }}
Loading