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