diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7d5534f..f68c55d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,23 +1,28 @@ -name: Publish NuGet (on push to main) +name: Create Release (on tag) + Publish to NuGet (OIDC) -# 触发条件:当有标签被推送到仓库时触发该工作流。 -# 支持任意格式的标签名,例如 `1.0.0` 或 `v1.0.0`。 +# 触发条件:当有标签被推送到仓库时触发该工作流(例如 v1.0.0 或 1.0.0) on: push: tags: - - '*' # 匹配所有标签推送事件 + - '*' -# 权限设置:授予写入 contents 的权限, -# 这样 GITHUB_TOKEN 才能调用 GitHub Releases API 创建发布。 +# 顶级权限:允许创建 Release(contents: write)和写 packages(如果需要) permissions: contents: write packages: write jobs: - publish: + build-and-publish: runs-on: ubuntu-latest + + # 允许此 job 请求短时 OIDC token(NuGet/login 使用) + permissions: + id-token: write + contents: write + packages: write + steps: - - name: Checkout repository + - name: Checkout repository (at tag) uses: actions/checkout@v4 with: fetch-depth: 0 @@ -43,17 +48,72 @@ jobs: - name: Show packages run: ls -la ./packages || true - - name: Publish to NuGet - env: - NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + - name: Get Version and Package Path + id: get_version run: | set -e - if [ -z "$(ls -A ./packages 2>/dev/null)" ]; then - echo "No packages found in ./packages" + PACKAGE_FILE=$(find ./packages -name "*.nupkg" | head -n 1) + if [ -z "$PACKAGE_FILE" ]; then + echo "No .nupkg file found in ./packages" exit 1 fi - echo "Publishing packages to nuget.org..." - dotnet nuget push "./packages/*.nupkg" \ - --api-key $NUGET_API_KEY \ + 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 + + # ----------------------- + # Get a short-lived NuGet API key via GitHub OIDC (NuGet login) + # ----------------------- + - name: NuGet login (OIDC → temp API key) + id: login + uses: NuGet/login@v1 + with: + # 推荐把用户名放到仓库 Secret(不是邮箱),例如 ${{ secrets.NUGET_USER }} + # 也可以直接写用户名(不推荐),但通常使用 secret 更安全 + user: ${{ secrets.NUGET_USER }} + + - name: NuGet push (using short-lived API key from NuGet/login) + run: | + set -e + PKG="${{ steps.get_version.outputs.package_file }}" + if [ -z "$PKG" ]; then + echo "No package to push" + exit 1 + fi + echo "Pushing $PKG to nuget.org (via OIDC short-lived key)..." + dotnet nuget push "$PKG" \ + --api-key "${{ steps.login.outputs.NUGET_API_KEY }}" \ --source https://api.nuget.org/v3/index.json \ --skip-duplicate + # 如果你希望在没有 NuGet/login outputs 的情况下也能失败得更清楚,可以在这里检查输出长度 + + # ----------------------- + # Create GitHub Release and upload .nupkg as asset + # ----------------------- + - name: Create GitHub Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref_name }} + release_name: "Release ${{ github.ref_name }}" + body: "Release created by CI for tag ${{ github.ref_name }} (package version ${{ steps.get_version.outputs.version }})" + draft: false + prerelease: false + + - name: Upload .nupkg to Release + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ${{ steps.get_version.outputs.package_file }} + asset_name: ${{ steps.get_version.outputs.package_basename }} + asset_content_type: application/octet-stream