From 9001e28b363c2e2a7db117cda3de11fafae1f741 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 1 Jan 2026 10:44:59 +0000 Subject: [PATCH] Add GitHub Actions workflow for NuGet releases Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .github/workflows/NUGET_RELEASE.md | 118 ++++++++++++++++++++++++++++ .github/workflows/nuget-release.yml | 95 ++++++++++++++++++++++ .gitignore | 1 + 3 files changed, 214 insertions(+) create mode 100644 .github/workflows/NUGET_RELEASE.md create mode 100644 .github/workflows/nuget-release.yml diff --git a/.github/workflows/NUGET_RELEASE.md b/.github/workflows/NUGET_RELEASE.md new file mode 100644 index 00000000..fb0f2be5 --- /dev/null +++ b/.github/workflows/NUGET_RELEASE.md @@ -0,0 +1,118 @@ +# NuGet Release Workflow + +This document describes the automated NuGet release workflow for SharpCompress. + +## Overview + +The `nuget-release.yml` workflow automatically builds, tests, and publishes SharpCompress packages to NuGet.org when changes are pushed to the `release` branch. + +## How It Works + +### Version Determination + +The workflow automatically determines the version based on whether the commit is tagged: + +1. **Tagged Release (Stable)**: + - If the current commit on the `release` branch has a version tag (e.g., `0.42.1`) + - Uses the tag as the version number + - Published as a stable release + - Creates a GitHub Release with the package attached + +2. **Untagged Release (Prerelease)**: + - If the current commit is NOT tagged + - Creates a prerelease version based on the last tag + - Format: `{LAST_TAG}-preview.{COMMIT_COUNT}+{SHORT_SHA}` + - Example: `0.42.1-preview.123+abc1234` + - Published as a prerelease to NuGet.org + +### Workflow Steps + +1. **Checkout**: Fetches the repository with full history for version detection +2. **Setup .NET**: Installs .NET 10.0 +3. **Determine Version**: Checks for tags and determines version +4. **Update Version**: Updates the version in the project file +5. **Build and Test**: Runs the full build and test suite +6. **Upload Artifacts**: Uploads the generated `.nupkg` files as workflow artifacts +7. **Push to NuGet**: Publishes the package to NuGet.org using the API key +8. **Create GitHub Release**: (Only for tagged releases) Creates a GitHub release with the package + +## Setup Requirements + +### 1. NuGet API Key Secret + +The workflow requires a `NUGET_API_KEY` secret to be configured in the repository settings: + +1. Go to https://www.nuget.org/account/apikeys +2. Create a new API key with "Push" permission for the SharpCompress package +3. In GitHub, go to: **Settings** → **Secrets and variables** → **Actions** +4. Create a new secret named `NUGET_API_KEY` with the API key value + +### 2. Branch Protection (Recommended) + +Consider enabling branch protection rules for the `release` branch to ensure: +- Code reviews are required before merging +- Status checks pass before merging +- Only authorized users can push to the branch + +## Usage + +### Creating a Stable Release + +1. Ensure all changes are merged and tested on the `release` branch +2. Create and push a version tag: + ```bash + git checkout release + git tag 0.43.0 + git push origin 0.43.0 + ``` +3. The workflow will automatically: + - Build and test the project + - Publish `SharpCompress 0.43.0` to NuGet.org + - Create a GitHub Release + +### Creating a Prerelease + +1. Push changes to the `release` branch without tagging: + ```bash + git checkout release + git push origin release + ``` +2. The workflow will automatically: + - Build and test the project + - Publish a prerelease version like `0.42.1-preview.456+abc1234` to NuGet.org + +## Troubleshooting + +### Workflow Fails to Push to NuGet + +- **Check the API Key**: Ensure `NUGET_API_KEY` is set correctly in repository secrets +- **Check API Key Permissions**: Verify the API key has "Push" permission for SharpCompress +- **Check API Key Expiration**: NuGet API keys may expire; create a new one if needed + +### Version Conflict + +If you see "Package already exists" errors: +- The workflow uses `--skip-duplicate` flag to handle this gracefully +- If you need to republish the same version, delete it from NuGet.org first (if allowed) + +### Build or Test Failures + +- The workflow will not push to NuGet if build or tests fail +- Check the workflow logs in GitHub Actions for details +- Fix the issues and push again + +## Manual Package Creation + +If you need to create a package manually without publishing: + +```bash +dotnet run --project build/build.csproj -- publish +``` + +The package will be created in the `artifacts/` directory. + +## Related Files + +- `.github/workflows/nuget-release.yml` - The workflow definition +- `src/SharpCompress/SharpCompress.csproj` - Project file with version information +- `build/Program.cs` - Build script that creates the NuGet package diff --git a/.github/workflows/nuget-release.yml b/.github/workflows/nuget-release.yml new file mode 100644 index 00000000..43653b94 --- /dev/null +++ b/.github/workflows/nuget-release.yml @@ -0,0 +1,95 @@ +name: NuGet Release + +on: + push: + branches: + - 'release' + +jobs: + build-and-publish: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 # Fetch all history for versioning + + - uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.0.x + + # Determine version based on whether the current commit is tagged + - name: Determine Version + id: version + run: | + # Check if current commit has a version tag + CURRENT_TAG=$(git tag --points-at HEAD | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' || echo "") + + if [[ -n "$CURRENT_TAG" ]]; then + # Tagged release - use the tag as version + VERSION="$CURRENT_TAG" + PRERELEASE=false + echo "Building tagged release version: $VERSION" + else + # Not tagged - create prerelease version based on last tag + LAST_TAG=$(git tag --list '[0-9]*.[0-9]*.[0-9]*' | sort -V | tail -1) + if [[ -z "$LAST_TAG" ]]; then + LAST_TAG="0.0.0" + fi + COMMIT_COUNT=$(git rev-list --count HEAD) + COMMIT_SHA=$(git rev-parse --short HEAD) + VERSION="${LAST_TAG}-preview.${COMMIT_COUNT}+${COMMIT_SHA}" + PRERELEASE=true + echo "Building prerelease version: $VERSION" + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "prerelease=$PRERELEASE" >> $GITHUB_OUTPUT + + # Update version in project file + - name: Update Version in Project + run: | + VERSION="${{ steps.version.outputs.version }}" + # Update VersionPrefix and remove VersionSuffix if present + sed -i "s|.*|$VERSION|g" src/SharpCompress/SharpCompress.csproj + sed -i "s|.*|${VERSION%%-*}|g" src/SharpCompress/SharpCompress.csproj + sed -i "s|.*|${VERSION%%-*}|g" src/SharpCompress/SharpCompress.csproj + echo "Updated project file with version $VERSION" + cat src/SharpCompress/SharpCompress.csproj | grep -E "(Version|FileVersion)" + + # Build and test + - name: Build and Test + run: dotnet run --project build/build.csproj + + # Upload artifacts for verification + - name: Upload NuGet Package + uses: actions/upload-artifact@v6 + with: + name: nuget-package + path: artifacts/*.nupkg + + # Push to NuGet.org + - name: Push to NuGet + if: success() + run: | + for package in artifacts/*.nupkg; do + echo "Pushing $package to NuGet.org" + dotnet nuget push "$package" \ + --api-key ${{ secrets.NUGET_API_KEY }} \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate + done + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + + # Create GitHub release for tagged versions + - name: Create GitHub Release + if: steps.version.outputs.prerelease == 'false' && success() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + VERSION="${{ steps.version.outputs.version }}" + gh release create "$VERSION" \ + artifacts/*.nupkg \ + --title "Release $VERSION" \ + --notes "Release $VERSION of SharpCompress" \ + --repo ${{ github.repository }} diff --git a/.gitignore b/.gitignore index 42a5e999..6c6a863d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ tests/TestArchives/*/Scratch2 .vs tools .idea/ +artifacts/ .DS_Store *.snupkg