# 发布工作流(NuGet + GitHub Release) # # 功能:当推送标签时自动构建、打包并发布到 NuGet.org 和 GitHub Release # 触发条件:推送任何标签(如 v1.0.0 或 1.0.0) # 权限:允许写入内容、包和使用 OIDC 身份验证 name: Publish (NuGet + 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: runs-on: ubuntu-latest permissions: id-token: write contents: write packages: write steps: - name: Checkout repository (at tag) uses: actions/checkout@v6 with: fetch-depth: 0 persist-credentials: true - name: Setup .NET uses: actions/setup-dotnet@v5 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 - 处理后的版本号 - name: Determine tag version id: tag_version run: | set -e echo "GITHUB_REF = ${GITHUB_REF}" TAG=${GITHUB_REF#refs/tags/} VERSION=${TAG#v} VERSION=${VERSION#V} echo "tag='$TAG' -> version='$VERSION'" 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: Upload compliance artifacts uses: actions/upload-artifact@v4 with: name: license-compliance path: | NOTICE THIRD_PARTY_LICENSES.md sbom.spdx.json sbom.cyclonedx.json sbom-spdx-validation.txt sbom-cyclonedx-validation.txt - name: Show packages run: ls -la ./packages || true - name: NuGet login (OIDC → temporary API key) id: nuget_login uses: NuGet/login@v1 with: user: ${{ secrets.NUGET_USER }} # 将所有生成的包推送到 nuget.org # 使用临时 API 密钥进行身份验证 # 跳过重复包的上传 - name: Push all packages to nuget.org env: NUGET_API_KEY: ${{ steps.nuget_login.outputs.NUGET_API_KEY }} run: | set -e echo "Found API key: ${NUGET_API_KEY:+*** present ***}" pushed_any=false for PKG in ./packages/*.nupkg; do [ -f "$PKG" ] || continue pushed_any=true echo "Pushing $PKG to nuget.org..." dotnet nuget push "$PKG" \ --api-key "${NUGET_API_KEY}" \ --source https://api.nuget.org/v3/index.json \ --skip-duplicate done 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 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=$(unzip -p "$PACKAGE_FILE" '*.nuspec' 2>/dev/null | sed -n 's:.*\(.*\).*:\1:p' | head -n1) if [ -z "$VERSION" ]; then echo "Failed to parse version from $PACKAGE_FILE" exit 1 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 # 使用从包中提取的版本信息和当前标签创建发布 # 发布包含描述信息和版本详情 - 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 }} ## Compliance - NOTICE - THIRD_PARTY_LICENSES - SPDX & CycloneDX SBOM draft: false prerelease: false files: | ./packages/*.nupkg NOTICE THIRD_PARTY_LICENSES.md sbom.spdx.json sbom.cyclonedx.json sbom-spdx-validation.txt sbom-cyclonedx-validation.txt env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}