From 24d651d7aef329681e666eeb110cfae997fc24a5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 1 Jan 2026 10:37:43 +0000 Subject: [PATCH 01/19] Initial plan 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 02/19] 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 From 2feabed29782f89e26418770205135d2b3acf78c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 1 Jan 2026 10:47:04 +0000 Subject: [PATCH 03/19] Remove redundant NUGET_API_KEY environment variable Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .github/workflows/TESTING.md | 126 ++++++++++++++++++++++++++++ .github/workflows/nuget-release.yml | 2 - 2 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/TESTING.md diff --git a/.github/workflows/TESTING.md b/.github/workflows/TESTING.md new file mode 100644 index 00000000..cc035a12 --- /dev/null +++ b/.github/workflows/TESTING.md @@ -0,0 +1,126 @@ +# Testing Guide for NuGet Release Workflow + +This document describes how to test the NuGet release workflow. + +## Testing Strategy + +Since this workflow publishes to NuGet.org and requires repository secrets, testing should be done carefully. + +## Pre-Testing Checklist + +- [x] Workflow YAML syntax validated +- [x] Version determination logic tested locally +- [x] Version update logic tested locally +- [x] Build script works (`dotnet run --project build/build.csproj`) + +## Manual Testing Steps + +### 1. Test Prerelease Publishing (Recommended First Test) + +This tests the workflow on untagged commits to the release branch. + +**Steps:** +1. Ensure `NUGET_API_KEY` secret is configured in repository settings +2. Create a test commit on the `release` branch (e.g., update a comment or README) +3. Push to the `release` branch +4. Monitor the GitHub Actions workflow at: https://github.com/adamhathcock/sharpcompress/actions +5. Verify: + - Workflow triggers and runs successfully + - Version is determined correctly (e.g., `0.42.1-preview.XXX+XXXXXXX`) + - Build and tests pass + - Package is uploaded as artifact + - Package is pushed to NuGet.org as prerelease + - No GitHub release is created (only for tagged releases) + +**Expected Outcome:** +- A new prerelease package appears on NuGet.org: https://www.nuget.org/packages/SharpCompress/ +- Package version follows pattern: `{LAST_TAG}-preview.{COMMIT_COUNT}+{SHA}` + +### 2. Test Tagged Release Publishing + +This tests the workflow when a version tag is pushed. + +**Steps:** +1. Prepare the `release` branch with all desired changes +2. Create a version tag (use a test version if possible, e.g., `0.42.2-test`): + ```bash + git checkout release + git tag 0.42.2-test + git push origin 0.42.2-test + ``` +3. Monitor the GitHub Actions workflow +4. Verify: + - Workflow triggers and runs successfully + - Version is determined as the tag (e.g., `0.42.2-test`) + - Build and tests pass + - Package is uploaded as artifact + - Package is pushed to NuGet.org as stable release + - GitHub release is created with the package attached + +**Expected Outcome:** +- A new stable release package appears on NuGet.org +- Package version matches the tag +- A GitHub release is created: https://github.com/adamhathcock/sharpcompress/releases + +### 3. Test Duplicate Package Handling + +This tests the `--skip-duplicate` flag behavior. + +**Steps:** +1. Push to the `release` branch without making changes +2. Monitor the workflow +3. Verify: + - Workflow runs but NuGet push is skipped with "duplicate" message + - No errors occur + +### 4. Test Build Failure Handling + +This tests that failed builds don't publish packages. + +**Steps:** +1. Introduce a breaking change in a test or code +2. Push to the `release` branch +3. Verify: + - Workflow runs and detects the failure + - Build or test step fails + - NuGet push step is skipped + - No package is published + +## Verification + +After each test, verify: + +1. **GitHub Actions Logs**: Check the workflow logs for any errors or warnings +2. **NuGet.org**: Verify the package appears with correct version and metadata +3. **GitHub Releases**: (For tagged releases) Verify the release is created with package attached +4. **Artifacts**: Download and inspect the uploaded artifacts + +## Rollback/Cleanup + +If testing produces unwanted packages: + +1. **Prerelease packages**: Can be unlisted on NuGet.org (Settings → Unlist) +2. **Stable packages**: Cannot be deleted, only unlisted (use test versions) +3. **GitHub Releases**: Can be deleted from GitHub releases page +4. **Tags**: Can be deleted with: + ```bash + git tag -d 0.42.2-test + git push origin :refs/tags/0.42.2-test + ``` + +## Known Limitations + +- NuGet.org does not allow re-uploading the same version +- Deleted packages on NuGet.org reserve the version number +- The workflow requires the `NUGET_API_KEY` secret to be set + +## Success Criteria + +The workflow is considered successful if: + +- ✅ Prerelease versions are published correctly with preview suffix +- ✅ Tagged versions are published as stable releases +- ✅ GitHub releases are created for tagged versions +- ✅ Build and test failures prevent publishing +- ✅ Duplicate packages are handled gracefully +- ✅ Workflow logs are clear and informative diff --git a/.github/workflows/nuget-release.yml b/.github/workflows/nuget-release.yml index 43653b94..9dce08e6 100644 --- a/.github/workflows/nuget-release.yml +++ b/.github/workflows/nuget-release.yml @@ -78,8 +78,6 @@ jobs: --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 From 2f874ace51aafea39dd78bf24e2bbe7cd1bba35e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 1 Jan 2026 10:48:32 +0000 Subject: [PATCH 04/19] Add comment clarifying sort -V usage Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .github/workflows/nuget-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/nuget-release.yml b/.github/workflows/nuget-release.yml index 9dce08e6..c2641089 100644 --- a/.github/workflows/nuget-release.yml +++ b/.github/workflows/nuget-release.yml @@ -32,6 +32,7 @@ jobs: echo "Building tagged release version: $VERSION" else # Not tagged - create prerelease version based on last tag + # Note: sort -V (version sort) is available in GNU coreutils on ubuntu-latest 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" From 9238cf112872a7529d17b04359375ed6289edde6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 1 Jan 2026 11:44:20 +0000 Subject: [PATCH 05/19] Move bash logic to C# build targets - Added determine-version, update-version, push-to-nuget, and create-release build targets - All version detection and publishing logic now in build/Program.cs - Workflow calls C# build targets instead of bash scripts - Updated documentation to reflect C# implementation Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .github/workflows/NUGET_RELEASE.md | 38 ++++- .github/workflows/nuget-release.yml | 66 ++------- build/Program.cs | 222 ++++++++++++++++++++++++++++ 3 files changed, 270 insertions(+), 56 deletions(-) diff --git a/.github/workflows/NUGET_RELEASE.md b/.github/workflows/NUGET_RELEASE.md index fb0f2be5..d79447fd 100644 --- a/.github/workflows/NUGET_RELEASE.md +++ b/.github/workflows/NUGET_RELEASE.md @@ -10,7 +10,7 @@ The `nuget-release.yml` workflow automatically builds, tests, and publishes Shar ### Version Determination -The workflow automatically determines the version based on whether the commit is tagged: +The workflow automatically determines the version based on whether the commit is tagged using C# code in the build project: 1. **Tagged Release (Stable)**: - If the current commit on the `release` branch has a version tag (e.g., `0.42.1`) @@ -29,12 +29,14 @@ The workflow automatically determines the version based on whether the commit is 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 +3. **Determine Version**: Runs `determine-version` build target to check for tags and determine version +4. **Update Version**: Runs `update-version` build target to update 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 +7. **Push to NuGet**: Runs `push-to-nuget` build target to publish the package to NuGet.org using the API key +8. **Create GitHub Release**: (Only for tagged releases) Runs `create-release` build target to create a GitHub release with the package + +All version detection, file updates, and publishing logic is implemented in C# in the `build/Program.cs` file using build targets. ## Setup Requirements @@ -111,8 +113,34 @@ dotnet run --project build/build.csproj -- publish The package will be created in the `artifacts/` directory. +## Build Targets + +The workflow uses the following C# build targets defined in `build/Program.cs`: + +- **determine-version**: Detects version from git tags and outputs VERSION and PRERELEASE variables +- **update-version**: Updates VersionPrefix, AssemblyVersion, and FileVersion in the project file +- **push-to-nuget**: Pushes the generated NuGet packages to NuGet.org (requires NUGET_API_KEY) +- **create-release**: Creates a GitHub release with the packages attached (requires GITHUB_TOKEN) + +These targets can be run manually for testing: + +```bash +# Determine the version +dotnet run --project build/build.csproj -- determine-version + +# Update version in project file +VERSION=0.43.0 dotnet run --project build/build.csproj -- update-version + +# Push to NuGet (requires NUGET_API_KEY environment variable) +NUGET_API_KEY=your-key dotnet run --project build/build.csproj -- push-to-nuget + +# Create GitHub release (requires GITHUB_TOKEN and VERSION environment variables) +GITHUB_TOKEN=your-token VERSION=0.43.0 PRERELEASE=false dotnet run --project build/build.csproj -- create-release +``` + ## Related Files - `.github/workflows/nuget-release.yml` - The workflow definition +- `build/Program.cs` - Build script with version detection and publishing logic - `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 index c2641089..3832777c 100644 --- a/.github/workflows/nuget-release.yml +++ b/.github/workflows/nuget-release.yml @@ -18,44 +18,16 @@ jobs: with: dotnet-version: 10.0.x - # Determine version based on whether the current commit is tagged + # Determine version using C# build target - 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 - # Note: sort -V (version sort) is available in GNU coreutils on ubuntu-latest - 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 + run: dotnet run --project build/build.csproj -- determine-version - # Update version in project file + # Update version in project file using C# build target - 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)" + run: dotnet run --project build/build.csproj -- update-version + env: + VERSION: ${{ steps.version.outputs.version }} # Build and test - name: Build and Test @@ -68,27 +40,19 @@ jobs: name: nuget-package path: artifacts/*.nupkg - # Push to NuGet.org + # Push to NuGet.org using C# build target - 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 + run: dotnet run --project build/build.csproj -- push-to-nuget + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} - # Create GitHub release for tagged versions + # Create GitHub release for tagged versions using C# build target - name: Create GitHub Release if: steps.version.outputs.prerelease == 'false' && success() + run: dotnet run --project build/build.csproj -- create-release 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 }} + VERSION: ${{ steps.version.outputs.version }} + PRERELEASE: ${{ steps.version.outputs.prerelease }} + GITHUB_REPOSITORY: ${{ github.repository }} diff --git a/build/Program.cs b/build/Program.cs index 92613d11..1081c855 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -1,7 +1,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; +using System.Linq; using System.Runtime.InteropServices; +using System.Text.RegularExpressions; using GlobExpressions; using static Bullseye.Targets; using static SimpleExec.Command; @@ -13,6 +16,10 @@ const string Test = "test"; const string Format = "format"; const string CheckFormat = "check-format"; const string Publish = "publish"; +const string DetermineVersion = "determine-version"; +const string UpdateVersion = "update-version"; +const string PushToNuGet = "push-to-nuget"; +const string CreateRelease = "create-release"; Target( Clean, @@ -99,6 +106,221 @@ Target( } ); +Target( + DetermineVersion, + () => + { + var (version, isPrerelease) = GetVersion(); + Console.WriteLine($"VERSION={version}"); + Console.WriteLine($"PRERELEASE={isPrerelease.ToString().ToLower()}"); + + // Write to environment file for GitHub Actions + var githubOutput = Environment.GetEnvironmentVariable("GITHUB_OUTPUT"); + if (!string.IsNullOrEmpty(githubOutput)) + { + File.AppendAllText(githubOutput, $"version={version}\n"); + File.AppendAllText(githubOutput, $"prerelease={isPrerelease.ToString().ToLower()}\n"); + } + } +); + +Target( + UpdateVersion, + () => + { + var version = Environment.GetEnvironmentVariable("VERSION"); + if (string.IsNullOrEmpty(version)) + { + var (detectedVersion, _) = GetVersion(); + version = detectedVersion; + } + + Console.WriteLine($"Updating project file with version: {version}"); + + var projectPath = "src/SharpCompress/SharpCompress.csproj"; + var content = File.ReadAllText(projectPath); + + // Get base version (without prerelease suffix) + var baseVersion = version.Split('-')[0]; + + // Update VersionPrefix + content = Regex.Replace( + content, + @"[^<]*", + $"{version}" + ); + + // Update AssemblyVersion + content = Regex.Replace( + content, + @"[^<]*", + $"{baseVersion}" + ); + + // Update FileVersion + content = Regex.Replace( + content, + @"[^<]*", + $"{baseVersion}" + ); + + File.WriteAllText(projectPath, content); + Console.WriteLine($"Updated VersionPrefix to: {version}"); + Console.WriteLine($"Updated AssemblyVersion and FileVersion to: {baseVersion}"); + } +); + +Target( + PushToNuGet, + () => + { + var apiKey = Environment.GetEnvironmentVariable("NUGET_API_KEY"); + if (string.IsNullOrEmpty(apiKey)) + { + Console.WriteLine( + "NUGET_API_KEY environment variable is not set. Skipping NuGet push." + ); + return; + } + + var packages = Directory.GetFiles("artifacts", "*.nupkg"); + if (packages.Length == 0) + { + Console.WriteLine("No packages found in artifacts directory."); + return; + } + + foreach (var package in packages) + { + Console.WriteLine($"Pushing {package} to NuGet.org"); + try + { + Run( + "dotnet", + $"nuget push \"{package}\" --api-key {apiKey} --source https://api.nuget.org/v3/index.json --skip-duplicate" + ); + } + catch (Exception ex) + { + Console.WriteLine($"Failed to push {package}: {ex.Message}"); + throw; + } + } + } +); + +Target( + CreateRelease, + () => + { + var version = Environment.GetEnvironmentVariable("VERSION"); + var isPrerelease = Environment.GetEnvironmentVariable("PRERELEASE"); + var githubToken = Environment.GetEnvironmentVariable("GITHUB_TOKEN"); + var githubRepository = Environment.GetEnvironmentVariable("GITHUB_REPOSITORY"); + + if (string.IsNullOrEmpty(version)) + { + var (detectedVersion, _) = GetVersion(); + version = detectedVersion; + } + + if (isPrerelease == "true") + { + Console.WriteLine("Skipping GitHub release creation for prerelease version."); + return; + } + + if (string.IsNullOrEmpty(githubToken)) + { + Console.WriteLine( + "GITHUB_TOKEN environment variable is not set. Skipping GitHub release creation." + ); + return; + } + + var packages = Directory.GetFiles("artifacts", "*.nupkg"); + var packageArgs = string.Join(" ", packages.Select(p => $"\"{p}\"")); + + var repo = string.IsNullOrEmpty(githubRepository) ? "" : $"--repo {githubRepository}"; + + Console.WriteLine($"Creating GitHub release for version {version}"); + try + { + Run( + "gh", + $"release create \"{version}\" {packageArgs} --title \"Release {version}\" --notes \"Release {version} of SharpCompress\" {repo}" + ); + } + catch (Exception ex) + { + Console.WriteLine($"Failed to create GitHub release: {ex.Message}"); + throw; + } + } +); + Target("default", [Publish], () => Console.WriteLine("Done!")); await RunTargetsAndExitAsync(args); + +static (string version, bool isPrerelease) GetVersion() +{ + // Check if current commit has a version tag + var currentTag = GetGitOutput("git tag --points-at HEAD") + .Split('\n', StringSplitOptions.RemoveEmptyEntries) + .FirstOrDefault(tag => Regex.IsMatch(tag.Trim(), @"^\d+\.\d+\.\d+$")); + + if (!string.IsNullOrEmpty(currentTag)) + { + // Tagged release - use the tag as version + var version = currentTag.Trim(); + Console.WriteLine($"Building tagged release version: {version}"); + return (version, false); + } + else + { + // Not tagged - create prerelease version based on last tag + var allTags = GetGitOutput("git tag --list") + .Split('\n', StringSplitOptions.RemoveEmptyEntries) + .Where(tag => Regex.IsMatch(tag.Trim(), @"^\d+\.\d+\.\d+$")) + .Select(tag => tag.Trim()) + .ToList(); + + var lastTag = allTags.OrderBy(tag => Version.Parse(tag)).LastOrDefault() ?? "0.0.0"; + + var commitCount = GetGitOutput("git rev-list --count HEAD").Trim(); + var commitSha = GetGitOutput("git rev-parse --short HEAD").Trim(); + + var version = $"{lastTag}-preview.{commitCount}+{commitSha}"; + Console.WriteLine($"Building prerelease version: {version}"); + return (version, true); + } +} + +static string GetGitOutput(string command) +{ + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "bash", + Arguments = $"-c \"{command}\"", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + }, + }; + + process.Start(); + var output = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + + if (process.ExitCode != 0) + { + var error = process.StandardError.ReadToEnd(); + throw new Exception($"Git command failed: {command}\n{error}"); + } + + return output; +} From bcf71370738d5489621a92143b5e225712bd59cb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 1 Jan 2026 11:48:25 +0000 Subject: [PATCH 06/19] Fix code review issues: use cross-platform git execution - Replaced bash-specific Process execution with SimpleExec's ReadAsync - Fixed git command execution to work on Windows and Linux - Added comment about API key handling in push-to-nuget target - Removed unused System.Diagnostics import Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- build/Program.cs | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/build/Program.cs b/build/Program.cs index 1081c855..f6819af8 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -195,6 +194,8 @@ Target( Console.WriteLine($"Pushing {package} to NuGet.org"); try { + // Note: API key is passed via command line argument which is standard practice for dotnet nuget push + // The key is already in an environment variable and not displayed in normal output Run( "dotnet", $"nuget push \"{package}\" --api-key {apiKey} --source https://api.nuget.org/v3/index.json --skip-duplicate" @@ -266,7 +267,7 @@ await RunTargetsAndExitAsync(args); static (string version, bool isPrerelease) GetVersion() { // Check if current commit has a version tag - var currentTag = GetGitOutput("git tag --points-at HEAD") + var currentTag = GetGitOutput("tag", "--points-at HEAD") .Split('\n', StringSplitOptions.RemoveEmptyEntries) .FirstOrDefault(tag => Regex.IsMatch(tag.Trim(), @"^\d+\.\d+\.\d+$")); @@ -280,7 +281,7 @@ static (string version, bool isPrerelease) GetVersion() else { // Not tagged - create prerelease version based on last tag - var allTags = GetGitOutput("git tag --list") + var allTags = GetGitOutput("tag", "--list") .Split('\n', StringSplitOptions.RemoveEmptyEntries) .Where(tag => Regex.IsMatch(tag.Trim(), @"^\d+\.\d+\.\d+$")) .Select(tag => tag.Trim()) @@ -288,8 +289,8 @@ static (string version, bool isPrerelease) GetVersion() var lastTag = allTags.OrderBy(tag => Version.Parse(tag)).LastOrDefault() ?? "0.0.0"; - var commitCount = GetGitOutput("git rev-list --count HEAD").Trim(); - var commitSha = GetGitOutput("git rev-parse --short HEAD").Trim(); + var commitCount = GetGitOutput("rev-list", "--count HEAD").Trim(); + var commitSha = GetGitOutput("rev-parse", "--short HEAD").Trim(); var version = $"{lastTag}-preview.{commitCount}+{commitSha}"; Console.WriteLine($"Building prerelease version: {version}"); @@ -297,30 +298,16 @@ static (string version, bool isPrerelease) GetVersion() } } -static string GetGitOutput(string command) +static string GetGitOutput(string command, string args) { - var process = new Process + try { - StartInfo = new ProcessStartInfo - { - FileName = "bash", - Arguments = $"-c \"{command}\"", - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false, - CreateNoWindow = true, - }, - }; - - process.Start(); - var output = process.StandardOutput.ReadToEnd(); - process.WaitForExit(); - - if (process.ExitCode != 0) - { - var error = process.StandardError.ReadToEnd(); - throw new Exception($"Git command failed: {command}\n{error}"); + // Use SimpleExec's Read to execute git commands in a cross-platform way + var (output, _) = ReadAsync("git", $"{command} {args}").GetAwaiter().GetResult(); + return output; + } + catch (Exception ex) + { + throw new Exception($"Git command failed: git {command} {args}\n{ex.Message}"); } - - return output; } From caa82a614631a3b619fb74973bcb39caaefd0804 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 1 Jan 2026 11:49:41 +0000 Subject: [PATCH 07/19] Remove duplicate entry in documentation Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .github/workflows/NUGET_RELEASE.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/NUGET_RELEASE.md b/.github/workflows/NUGET_RELEASE.md index d79447fd..f19a662a 100644 --- a/.github/workflows/NUGET_RELEASE.md +++ b/.github/workflows/NUGET_RELEASE.md @@ -143,4 +143,3 @@ GITHUB_TOKEN=your-token VERSION=0.43.0 PRERELEASE=false dotnet run --project bui - `.github/workflows/nuget-release.yml` - The workflow definition - `build/Program.cs` - Build script with version detection and publishing logic - `src/SharpCompress/SharpCompress.csproj` - Project file with version information -- `build/Program.cs` - Build script that creates the NuGet package From 7f71f76f6e36d5bdb0c978692a17ce9217a71025 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 2 Jan 2026 18:03:18 +0000 Subject: [PATCH 08/19] Remove SHA from prerelease version, use only commit count - Changed prerelease version format from {LAST_TAG}-preview.{COMMIT_COUNT}+{SHA} to {LAST_TAG}-preview.{COMMIT_COUNT} - Updated documentation in NUGET_RELEASE.md and TESTING.md to reflect the change - Removed git rev-parse call for short SHA since it's no longer needed Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .github/workflows/NUGET_RELEASE.md | 6 +++--- .github/workflows/TESTING.md | 4 ++-- build/Program.cs | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/NUGET_RELEASE.md b/.github/workflows/NUGET_RELEASE.md index f19a662a..bff4c37f 100644 --- a/.github/workflows/NUGET_RELEASE.md +++ b/.github/workflows/NUGET_RELEASE.md @@ -21,8 +21,8 @@ The workflow automatically determines the version based on whether the commit is 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` + - Format: `{LAST_TAG}-preview.{COMMIT_COUNT}` + - Example: `0.42.1-preview.123` - Published as a prerelease to NuGet.org ### Workflow Steps @@ -81,7 +81,7 @@ Consider enabling branch protection rules for the `release` branch to ensure: ``` 2. The workflow will automatically: - Build and test the project - - Publish a prerelease version like `0.42.1-preview.456+abc1234` to NuGet.org + - Publish a prerelease version like `0.42.1-preview.456` to NuGet.org ## Troubleshooting diff --git a/.github/workflows/TESTING.md b/.github/workflows/TESTING.md index cc035a12..6168e99e 100644 --- a/.github/workflows/TESTING.md +++ b/.github/workflows/TESTING.md @@ -26,7 +26,7 @@ This tests the workflow on untagged commits to the release branch. 4. Monitor the GitHub Actions workflow at: https://github.com/adamhathcock/sharpcompress/actions 5. Verify: - Workflow triggers and runs successfully - - Version is determined correctly (e.g., `0.42.1-preview.XXX+XXXXXXX`) + - Version is determined correctly (e.g., `0.42.1-preview.XXX`) - Build and tests pass - Package is uploaded as artifact - Package is pushed to NuGet.org as prerelease @@ -34,7 +34,7 @@ This tests the workflow on untagged commits to the release branch. **Expected Outcome:** - A new prerelease package appears on NuGet.org: https://www.nuget.org/packages/SharpCompress/ -- Package version follows pattern: `{LAST_TAG}-preview.{COMMIT_COUNT}+{SHA}` +- Package version follows pattern: `{LAST_TAG}-preview.{COMMIT_COUNT}` ### 2. Test Tagged Release Publishing diff --git a/build/Program.cs b/build/Program.cs index f6819af8..dc8c11f3 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -290,9 +290,8 @@ static (string version, bool isPrerelease) GetVersion() var lastTag = allTags.OrderBy(tag => Version.Parse(tag)).LastOrDefault() ?? "0.0.0"; var commitCount = GetGitOutput("rev-list", "--count HEAD").Trim(); - var commitSha = GetGitOutput("rev-parse", "--short HEAD").Trim(); - var version = $"{lastTag}-preview.{commitCount}+{commitSha}"; + var version = $"{lastTag}-preview.{commitCount}"; Console.WriteLine($"Building prerelease version: {version}"); return (version, true); } From d5913e8371eef6f4ff3212ffba64310db02d9514 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 2 Jan 2026 18:04:13 +0000 Subject: [PATCH 09/19] Fix TESTING.md to use valid version tag format - Changed example from 0.42.2-test to 0.42.2 to match regex pattern - Added note that tags must be pure semantic versions (MAJOR.MINOR.PATCH) - Addresses bot review feedback about documentation inconsistency Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .github/workflows/TESTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/TESTING.md b/.github/workflows/TESTING.md index 6168e99e..89d0d1e3 100644 --- a/.github/workflows/TESTING.md +++ b/.github/workflows/TESTING.md @@ -42,16 +42,16 @@ This tests the workflow when a version tag is pushed. **Steps:** 1. Prepare the `release` branch with all desired changes -2. Create a version tag (use a test version if possible, e.g., `0.42.2-test`): +2. Create a version tag (must be a pure semantic version like `MAJOR.MINOR.PATCH`): ```bash git checkout release - git tag 0.42.2-test - git push origin 0.42.2-test + git tag 0.42.2 + git push origin 0.42.2 ``` 3. Monitor the GitHub Actions workflow 4. Verify: - Workflow triggers and runs successfully - - Version is determined as the tag (e.g., `0.42.2-test`) + - Version is determined as the tag (e.g., `0.42.2`) - Build and tests pass - Package is uploaded as artifact - Package is pushed to NuGet.org as stable release From 9d6cd930eabfc2c1ae2db65db963bf8e54bbe5f5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 11:23:32 +0000 Subject: [PATCH 10/19] Use next minor version with beta suffix for prereleases - Changed prerelease versioning to increment minor version instead of using last tag - Changed suffix from "preview" to "beta" - Format is now {NEXT_MINOR_VERSION}-beta.{COMMIT_COUNT} - Example: 0.43.0-beta.123 (if last tag is 0.42.x) - Updated documentation in NUGET_RELEASE.md and TESTING.md Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .github/workflows/NUGET_RELEASE.md | 8 ++++---- .github/workflows/TESTING.md | 6 +++--- build/Program.cs | 8 ++++++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/NUGET_RELEASE.md b/.github/workflows/NUGET_RELEASE.md index bff4c37f..56cd874e 100644 --- a/.github/workflows/NUGET_RELEASE.md +++ b/.github/workflows/NUGET_RELEASE.md @@ -20,9 +20,9 @@ The workflow automatically determines the version based on whether the commit is 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}` - - Example: `0.42.1-preview.123` + - Creates a prerelease version based on the next minor version + - Format: `{NEXT_MINOR_VERSION}-beta.{COMMIT_COUNT}` + - Example: `0.43.0-beta.123` (if last tag is 0.42.x) - Published as a prerelease to NuGet.org ### Workflow Steps @@ -81,7 +81,7 @@ Consider enabling branch protection rules for the `release` branch to ensure: ``` 2. The workflow will automatically: - Build and test the project - - Publish a prerelease version like `0.42.1-preview.456` to NuGet.org + - Publish a prerelease version like `0.43.0-beta.456` to NuGet.org ## Troubleshooting diff --git a/.github/workflows/TESTING.md b/.github/workflows/TESTING.md index 89d0d1e3..af9044d5 100644 --- a/.github/workflows/TESTING.md +++ b/.github/workflows/TESTING.md @@ -26,7 +26,7 @@ This tests the workflow on untagged commits to the release branch. 4. Monitor the GitHub Actions workflow at: https://github.com/adamhathcock/sharpcompress/actions 5. Verify: - Workflow triggers and runs successfully - - Version is determined correctly (e.g., `0.42.1-preview.XXX`) + - Version is determined correctly (e.g., `0.43.0-beta.XXX` if last tag is 0.42.x) - Build and tests pass - Package is uploaded as artifact - Package is pushed to NuGet.org as prerelease @@ -34,7 +34,7 @@ This tests the workflow on untagged commits to the release branch. **Expected Outcome:** - A new prerelease package appears on NuGet.org: https://www.nuget.org/packages/SharpCompress/ -- Package version follows pattern: `{LAST_TAG}-preview.{COMMIT_COUNT}` +- Package version follows pattern: `{NEXT_MINOR_VERSION}-beta.{COMMIT_COUNT}` ### 2. Test Tagged Release Publishing @@ -118,7 +118,7 @@ If testing produces unwanted packages: The workflow is considered successful if: -- ✅ Prerelease versions are published correctly with preview suffix +- ✅ Prerelease versions are published correctly with beta suffix - ✅ Tagged versions are published as stable releases - ✅ GitHub releases are created for tagged versions - ✅ Build and test failures prevent publishing diff --git a/build/Program.cs b/build/Program.cs index dc8c11f3..40c19b4a 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -280,7 +280,7 @@ static (string version, bool isPrerelease) GetVersion() } else { - // Not tagged - create prerelease version based on last tag + // Not tagged - create prerelease version based on next minor version var allTags = GetGitOutput("tag", "--list") .Split('\n', StringSplitOptions.RemoveEmptyEntries) .Where(tag => Regex.IsMatch(tag.Trim(), @"^\d+\.\d+\.\d+$")) @@ -288,10 +288,14 @@ static (string version, bool isPrerelease) GetVersion() .ToList(); var lastTag = allTags.OrderBy(tag => Version.Parse(tag)).LastOrDefault() ?? "0.0.0"; + var lastVersion = Version.Parse(lastTag); + + // Increment minor version for next release + var nextVersion = new Version(lastVersion.Major, lastVersion.Minor + 1, 0); var commitCount = GetGitOutput("rev-list", "--count HEAD").Trim(); - var version = $"{lastTag}-preview.{commitCount}"; + var version = $"{nextVersion}-beta.{commitCount}"; Console.WriteLine($"Building prerelease version: {version}"); return (version, true); } From 975f5f4b4cf10d465b05b7027dce4d75f19ef5c3 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sat, 3 Jan 2026 12:35:34 +0000 Subject: [PATCH 11/19] make things async --- build/Program.cs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/build/Program.cs b/build/Program.cs index 40c19b4a..dadd1516 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text.RegularExpressions; +using System.Threading.Tasks; using GlobExpressions; using static Bullseye.Targets; using static SimpleExec.Command; @@ -107,9 +108,9 @@ Target( Target( DetermineVersion, - () => + async () => { - var (version, isPrerelease) = GetVersion(); + var (version, isPrerelease) = await GetVersion(); Console.WriteLine($"VERSION={version}"); Console.WriteLine($"PRERELEASE={isPrerelease.ToString().ToLower()}"); @@ -125,12 +126,12 @@ Target( Target( UpdateVersion, - () => + async () => { var version = Environment.GetEnvironmentVariable("VERSION"); if (string.IsNullOrEmpty(version)) { - var (detectedVersion, _) = GetVersion(); + var (detectedVersion, _) = await GetVersion(); version = detectedVersion; } @@ -212,7 +213,7 @@ Target( Target( CreateRelease, - () => + async () => { var version = Environment.GetEnvironmentVariable("VERSION"); var isPrerelease = Environment.GetEnvironmentVariable("PRERELEASE"); @@ -221,7 +222,7 @@ Target( if (string.IsNullOrEmpty(version)) { - var (detectedVersion, _) = GetVersion(); + var (detectedVersion, _) = await GetVersion(); version = detectedVersion; } @@ -264,10 +265,10 @@ Target("default", [Publish], () => Console.WriteLine("Done!")); await RunTargetsAndExitAsync(args); -static (string version, bool isPrerelease) GetVersion() +static async Task<(string version, bool isPrerelease)> GetVersion() { // Check if current commit has a version tag - var currentTag = GetGitOutput("tag", "--points-at HEAD") + var currentTag = (await GetGitOutput("tag", "--points-at HEAD")) .Split('\n', StringSplitOptions.RemoveEmptyEntries) .FirstOrDefault(tag => Regex.IsMatch(tag.Trim(), @"^\d+\.\d+\.\d+$")); @@ -281,7 +282,7 @@ static (string version, bool isPrerelease) GetVersion() else { // Not tagged - create prerelease version based on next minor version - var allTags = GetGitOutput("tag", "--list") + var allTags = (await GetGitOutput("tag", "--list")) .Split('\n', StringSplitOptions.RemoveEmptyEntries) .Where(tag => Regex.IsMatch(tag.Trim(), @"^\d+\.\d+\.\d+$")) .Select(tag => tag.Trim()) @@ -293,7 +294,7 @@ static (string version, bool isPrerelease) GetVersion() // Increment minor version for next release var nextVersion = new Version(lastVersion.Major, lastVersion.Minor + 1, 0); - var commitCount = GetGitOutput("rev-list", "--count HEAD").Trim(); + var commitCount = (await GetGitOutput("rev-list", "--count HEAD")).Trim(); var version = $"{nextVersion}-beta.{commitCount}"; Console.WriteLine($"Building prerelease version: {version}"); @@ -301,12 +302,12 @@ static (string version, bool isPrerelease) GetVersion() } } -static string GetGitOutput(string command, string args) +static async Task GetGitOutput(string command, string args) { try { // Use SimpleExec's Read to execute git commands in a cross-platform way - var (output, _) = ReadAsync("git", $"{command} {args}").GetAwaiter().GetResult(); + var (output, _) = await ReadAsync("git", $"{command} {args}"); return output; } catch (Exception ex) From 091a800c9d2d7c0626678d78a29ace0681e156a6 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sat, 3 Jan 2026 12:36:50 +0000 Subject: [PATCH 12/19] Potential fix for code scanning alert no. 6: Workflow does not contain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/nuget-release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/nuget-release.yml b/.github/workflows/nuget-release.yml index 3832777c..a1bf03c6 100644 --- a/.github/workflows/nuget-release.yml +++ b/.github/workflows/nuget-release.yml @@ -8,6 +8,8 @@ on: jobs: build-and-publish: runs-on: ubuntu-latest + permissions: + contents: write steps: - uses: actions/checkout@v6 From f1b305f68278c12169a459a0e879824624508fbe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 12:54:05 +0000 Subject: [PATCH 13/19] Add matrix build and master branch support to release workflow - Workflow now triggers on both master and release branches - Added matrix strategy for windows-latest and ubuntu-latest - Both OS platforms build and test the project - Only Windows build publishes to NuGet and creates GitHub releases - Upload artifacts are now OS-specific (windows-latest-nuget-package, ubuntu-latest-nuget-package) - Updated documentation to reflect multi-platform builds and master branch support Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .github/workflows/NUGET_RELEASE.md | 38 +++++++++++++++-------------- .github/workflows/TESTING.md | 30 +++++++++++------------ .github/workflows/nuget-release.yml | 16 +++++++----- 3 files changed, 45 insertions(+), 39 deletions(-) diff --git a/.github/workflows/NUGET_RELEASE.md b/.github/workflows/NUGET_RELEASE.md index 56cd874e..3b2a0763 100644 --- a/.github/workflows/NUGET_RELEASE.md +++ b/.github/workflows/NUGET_RELEASE.md @@ -4,7 +4,7 @@ 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. +The `nuget-release.yml` workflow automatically builds, tests, and publishes SharpCompress packages to NuGet.org when changes are pushed to the `master` or `release` branch. The workflow runs on both Windows and Ubuntu, but only the Windows build publishes to NuGet. ## How It Works @@ -13,28 +13,30 @@ The `nuget-release.yml` workflow automatically builds, tests, and publishes Shar The workflow automatically determines the version based on whether the commit is tagged using C# code in the build project: 1. **Tagged Release (Stable)**: - - If the current commit on the `release` branch has a version tag (e.g., `0.42.1`) + - If the current commit 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 + - Creates a GitHub Release with the package attached (Windows build only) 2. **Untagged Release (Prerelease)**: - If the current commit is NOT tagged - Creates a prerelease version based on the next minor version - Format: `{NEXT_MINOR_VERSION}-beta.{COMMIT_COUNT}` - Example: `0.43.0-beta.123` (if last tag is 0.42.x) - - Published as a prerelease to NuGet.org + - Published as a prerelease to NuGet.org (Windows build only) ### Workflow Steps +The workflow runs on a matrix of operating systems (Windows and Ubuntu): + 1. **Checkout**: Fetches the repository with full history for version detection 2. **Setup .NET**: Installs .NET 10.0 3. **Determine Version**: Runs `determine-version` build target to check for tags and determine version 4. **Update Version**: Runs `update-version` build target to update 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**: Runs `push-to-nuget` build target to publish the package to NuGet.org using the API key -8. **Create GitHub Release**: (Only for tagged releases) Runs `create-release` build target to create a GitHub release with the package +5. **Build and Test**: Runs the full build and test suite on both platforms +6. **Upload Artifacts**: Uploads the generated `.nupkg` files as workflow artifacts (separate for each OS) +7. **Push to NuGet**: (Windows only) Runs `push-to-nuget` build target to publish the package to NuGet.org using the API key +8. **Create GitHub Release**: (Windows only, tagged releases only) Runs `create-release` build target to create a GitHub release with the package All version detection, file updates, and publishing logic is implemented in C# in the `build/Program.cs` file using build targets. @@ -60,28 +62,28 @@ Consider enabling branch protection rules for the `release` branch to ensure: ### Creating a Stable Release -1. Ensure all changes are merged and tested on the `release` branch +1. Ensure all changes are merged and tested on the `master` or `release` branch 2. Create and push a version tag: ```bash - git checkout release + git checkout master # or 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 + - Build and test the project on both Windows and Ubuntu + - Publish `SharpCompress 0.43.0` to NuGet.org (Windows build) + - Create a GitHub Release (Windows build) ### Creating a Prerelease -1. Push changes to the `release` branch without tagging: +1. Push changes to the `master` or `release` branch without tagging: ```bash - git checkout release - git push origin release + git checkout master # or release + git push origin master # or release ``` 2. The workflow will automatically: - - Build and test the project - - Publish a prerelease version like `0.43.0-beta.456` to NuGet.org + - Build and test the project on both Windows and Ubuntu + - Publish a prerelease version like `0.43.0-beta.456` to NuGet.org (Windows build) ## Troubleshooting diff --git a/.github/workflows/TESTING.md b/.github/workflows/TESTING.md index af9044d5..fa32c1d6 100644 --- a/.github/workflows/TESTING.md +++ b/.github/workflows/TESTING.md @@ -4,7 +4,7 @@ This document describes how to test the NuGet release workflow. ## Testing Strategy -Since this workflow publishes to NuGet.org and requires repository secrets, testing should be done carefully. +Since this workflow publishes to NuGet.org and requires repository secrets, testing should be done carefully. The workflow runs on both Windows and Ubuntu, but only the Windows build publishes to NuGet. ## Pre-Testing Checklist @@ -17,19 +17,19 @@ Since this workflow publishes to NuGet.org and requires repository secrets, test ### 1. Test Prerelease Publishing (Recommended First Test) -This tests the workflow on untagged commits to the release branch. +This tests the workflow on untagged commits to the master or release branch. **Steps:** 1. Ensure `NUGET_API_KEY` secret is configured in repository settings -2. Create a test commit on the `release` branch (e.g., update a comment or README) -3. Push to the `release` branch +2. Create a test commit on the `master` or `release` branch (e.g., update a comment or README) +3. Push to the `master` or `release` branch 4. Monitor the GitHub Actions workflow at: https://github.com/adamhathcock/sharpcompress/actions 5. Verify: - - Workflow triggers and runs successfully + - Workflow triggers and runs successfully on both Windows and Ubuntu - Version is determined correctly (e.g., `0.43.0-beta.XXX` if last tag is 0.42.x) - - Build and tests pass - - Package is uploaded as artifact - - Package is pushed to NuGet.org as prerelease + - Build and tests pass on both platforms + - Package artifacts are uploaded for both platforms + - Package is pushed to NuGet.org as prerelease (Windows build only) - No GitHub release is created (only for tagged releases) **Expected Outcome:** @@ -41,21 +41,21 @@ This tests the workflow on untagged commits to the release branch. This tests the workflow when a version tag is pushed. **Steps:** -1. Prepare the `release` branch with all desired changes +1. Prepare the `master` or `release` branch with all desired changes 2. Create a version tag (must be a pure semantic version like `MAJOR.MINOR.PATCH`): ```bash - git checkout release + git checkout master # or release git tag 0.42.2 git push origin 0.42.2 ``` 3. Monitor the GitHub Actions workflow 4. Verify: - - Workflow triggers and runs successfully + - Workflow triggers and runs successfully on both Windows and Ubuntu - Version is determined as the tag (e.g., `0.42.2`) - - Build and tests pass - - Package is uploaded as artifact - - Package is pushed to NuGet.org as stable release - - GitHub release is created with the package attached + - Build and tests pass on both platforms + - Package artifacts are uploaded for both platforms + - Package is pushed to NuGet.org as stable release (Windows build only) + - GitHub release is created with the package attached (Windows build only) **Expected Outcome:** - A new stable release package appears on NuGet.org diff --git a/.github/workflows/nuget-release.yml b/.github/workflows/nuget-release.yml index a1bf03c6..fe818b38 100644 --- a/.github/workflows/nuget-release.yml +++ b/.github/workflows/nuget-release.yml @@ -3,13 +3,17 @@ name: NuGet Release on: push: branches: + - 'master' - 'release' jobs: build-and-publish: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} permissions: contents: write + strategy: + matrix: + os: [windows-latest, ubuntu-latest] steps: - uses: actions/checkout@v6 @@ -39,19 +43,19 @@ jobs: - name: Upload NuGet Package uses: actions/upload-artifact@v6 with: - name: nuget-package + name: ${{ matrix.os }}-nuget-package path: artifacts/*.nupkg - # Push to NuGet.org using C# build target + # Push to NuGet.org using C# build target (Windows only) - name: Push to NuGet - if: success() + if: success() && matrix.os == 'windows-latest' run: dotnet run --project build/build.csproj -- push-to-nuget env: NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} - # Create GitHub release for tagged versions using C# build target + # Create GitHub release for tagged versions using C# build target (Windows only) - name: Create GitHub Release - if: steps.version.outputs.prerelease == 'false' && success() + if: steps.version.outputs.prerelease == 'false' && success() && matrix.os == 'windows-latest' run: dotnet run --project build/build.csproj -- create-release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 9794c8ba722cab9cd5cfa98e9c2c24c0dac9529f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 13:19:23 +0000 Subject: [PATCH 14/19] Remove GitHub release creation - will be done manually - Removed create-release build target from build/Program.cs - Removed CreateRelease constant - Removed "Create GitHub Release" step from workflow - Removed permissions: contents: write since no longer creating releases - Updated NUGET_RELEASE.md to remove all references to GitHub release creation - Updated TESTING.md to remove GitHub release verification steps - GitHub releases will now be created manually instead of automatically Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .github/workflows/NUGET_RELEASE.md | 7 ---- .github/workflows/TESTING.md | 14 +++----- .github/workflows/nuget-release.yml | 12 ------- build/Program.cs | 51 ----------------------------- 4 files changed, 4 insertions(+), 80 deletions(-) diff --git a/.github/workflows/NUGET_RELEASE.md b/.github/workflows/NUGET_RELEASE.md index 3b2a0763..8fa18710 100644 --- a/.github/workflows/NUGET_RELEASE.md +++ b/.github/workflows/NUGET_RELEASE.md @@ -16,7 +16,6 @@ The workflow automatically determines the version based on whether the commit is - If the current commit 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 (Windows build only) 2. **Untagged Release (Prerelease)**: - If the current commit is NOT tagged @@ -36,7 +35,6 @@ The workflow runs on a matrix of operating systems (Windows and Ubuntu): 5. **Build and Test**: Runs the full build and test suite on both platforms 6. **Upload Artifacts**: Uploads the generated `.nupkg` files as workflow artifacts (separate for each OS) 7. **Push to NuGet**: (Windows only) Runs `push-to-nuget` build target to publish the package to NuGet.org using the API key -8. **Create GitHub Release**: (Windows only, tagged releases only) Runs `create-release` build target to create a GitHub release with the package All version detection, file updates, and publishing logic is implemented in C# in the `build/Program.cs` file using build targets. @@ -72,7 +70,6 @@ Consider enabling branch protection rules for the `release` branch to ensure: 3. The workflow will automatically: - Build and test the project on both Windows and Ubuntu - Publish `SharpCompress 0.43.0` to NuGet.org (Windows build) - - Create a GitHub Release (Windows build) ### Creating a Prerelease @@ -122,7 +119,6 @@ The workflow uses the following C# build targets defined in `build/Program.cs`: - **determine-version**: Detects version from git tags and outputs VERSION and PRERELEASE variables - **update-version**: Updates VersionPrefix, AssemblyVersion, and FileVersion in the project file - **push-to-nuget**: Pushes the generated NuGet packages to NuGet.org (requires NUGET_API_KEY) -- **create-release**: Creates a GitHub release with the packages attached (requires GITHUB_TOKEN) These targets can be run manually for testing: @@ -135,9 +131,6 @@ VERSION=0.43.0 dotnet run --project build/build.csproj -- update-version # Push to NuGet (requires NUGET_API_KEY environment variable) NUGET_API_KEY=your-key dotnet run --project build/build.csproj -- push-to-nuget - -# Create GitHub release (requires GITHUB_TOKEN and VERSION environment variables) -GITHUB_TOKEN=your-token VERSION=0.43.0 PRERELEASE=false dotnet run --project build/build.csproj -- create-release ``` ## Related Files diff --git a/.github/workflows/TESTING.md b/.github/workflows/TESTING.md index fa32c1d6..6afaa8aa 100644 --- a/.github/workflows/TESTING.md +++ b/.github/workflows/TESTING.md @@ -30,7 +30,6 @@ This tests the workflow on untagged commits to the master or release branch. - Build and tests pass on both platforms - Package artifacts are uploaded for both platforms - Package is pushed to NuGet.org as prerelease (Windows build only) - - No GitHub release is created (only for tagged releases) **Expected Outcome:** - A new prerelease package appears on NuGet.org: https://www.nuget.org/packages/SharpCompress/ @@ -55,12 +54,10 @@ This tests the workflow when a version tag is pushed. - Build and tests pass on both platforms - Package artifacts are uploaded for both platforms - Package is pushed to NuGet.org as stable release (Windows build only) - - GitHub release is created with the package attached (Windows build only) **Expected Outcome:** - A new stable release package appears on NuGet.org - Package version matches the tag -- A GitHub release is created: https://github.com/adamhathcock/sharpcompress/releases ### 3. Test Duplicate Package Handling @@ -92,8 +89,7 @@ After each test, verify: 1. **GitHub Actions Logs**: Check the workflow logs for any errors or warnings 2. **NuGet.org**: Verify the package appears with correct version and metadata -3. **GitHub Releases**: (For tagged releases) Verify the release is created with package attached -4. **Artifacts**: Download and inspect the uploaded artifacts +3. **Artifacts**: Download and inspect the uploaded artifacts ## Rollback/Cleanup @@ -101,11 +97,10 @@ If testing produces unwanted packages: 1. **Prerelease packages**: Can be unlisted on NuGet.org (Settings → Unlist) 2. **Stable packages**: Cannot be deleted, only unlisted (use test versions) -3. **GitHub Releases**: Can be deleted from GitHub releases page -4. **Tags**: Can be deleted with: +3. **Tags**: Can be deleted with: ```bash - git tag -d 0.42.2-test - git push origin :refs/tags/0.42.2-test + git tag -d 0.42.2 + git push origin :refs/tags/0.42.2 ``` ## Known Limitations @@ -120,7 +115,6 @@ The workflow is considered successful if: - ✅ Prerelease versions are published correctly with beta suffix - ✅ Tagged versions are published as stable releases -- ✅ GitHub releases are created for tagged versions - ✅ Build and test failures prevent publishing - ✅ Duplicate packages are handled gracefully - ✅ Workflow logs are clear and informative diff --git a/.github/workflows/nuget-release.yml b/.github/workflows/nuget-release.yml index fe818b38..945b8a05 100644 --- a/.github/workflows/nuget-release.yml +++ b/.github/workflows/nuget-release.yml @@ -9,8 +9,6 @@ on: jobs: build-and-publish: runs-on: ${{ matrix.os }} - permissions: - contents: write strategy: matrix: os: [windows-latest, ubuntu-latest] @@ -52,13 +50,3 @@ jobs: run: dotnet run --project build/build.csproj -- push-to-nuget env: NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} - - # Create GitHub release for tagged versions using C# build target (Windows only) - - name: Create GitHub Release - if: steps.version.outputs.prerelease == 'false' && success() && matrix.os == 'windows-latest' - run: dotnet run --project build/build.csproj -- create-release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VERSION: ${{ steps.version.outputs.version }} - PRERELEASE: ${{ steps.version.outputs.prerelease }} - GITHUB_REPOSITORY: ${{ github.repository }} diff --git a/build/Program.cs b/build/Program.cs index dadd1516..f88c67d9 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -19,7 +19,6 @@ const string Publish = "publish"; const string DetermineVersion = "determine-version"; const string UpdateVersion = "update-version"; const string PushToNuGet = "push-to-nuget"; -const string CreateRelease = "create-release"; Target( Clean, @@ -211,56 +210,6 @@ Target( } ); -Target( - CreateRelease, - async () => - { - var version = Environment.GetEnvironmentVariable("VERSION"); - var isPrerelease = Environment.GetEnvironmentVariable("PRERELEASE"); - var githubToken = Environment.GetEnvironmentVariable("GITHUB_TOKEN"); - var githubRepository = Environment.GetEnvironmentVariable("GITHUB_REPOSITORY"); - - if (string.IsNullOrEmpty(version)) - { - var (detectedVersion, _) = await GetVersion(); - version = detectedVersion; - } - - if (isPrerelease == "true") - { - Console.WriteLine("Skipping GitHub release creation for prerelease version."); - return; - } - - if (string.IsNullOrEmpty(githubToken)) - { - Console.WriteLine( - "GITHUB_TOKEN environment variable is not set. Skipping GitHub release creation." - ); - return; - } - - var packages = Directory.GetFiles("artifacts", "*.nupkg"); - var packageArgs = string.Join(" ", packages.Select(p => $"\"{p}\"")); - - var repo = string.IsNullOrEmpty(githubRepository) ? "" : $"--repo {githubRepository}"; - - Console.WriteLine($"Creating GitHub release for version {version}"); - try - { - Run( - "gh", - $"release create \"{version}\" {packageArgs} --title \"Release {version}\" --notes \"Release {version} of SharpCompress\" {repo}" - ); - } - catch (Exception ex) - { - Console.WriteLine($"Failed to create GitHub release: {ex.Message}"); - throw; - } - } -); - Target("default", [Publish], () => Console.WriteLine("Done!")); await RunTargetsAndExitAsync(args); From 29f8b512c42328ed5ad2026a8d3dc8d21c827866 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sat, 3 Jan 2026 13:23:13 +0000 Subject: [PATCH 15/19] Potential fix for code scanning alert no. 7: Workflow does not contain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/nuget-release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/nuget-release.yml b/.github/workflows/nuget-release.yml index 945b8a05..f1cb8f73 100644 --- a/.github/workflows/nuget-release.yml +++ b/.github/workflows/nuget-release.yml @@ -6,6 +6,9 @@ on: - 'master' - 'release' +permissions: + contents: read + jobs: build-and-publish: runs-on: ${{ matrix.os }} From 29cb1fed12d0edced4104912df8ed339c9f89b26 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sat, 3 Jan 2026 13:29:05 +0000 Subject: [PATCH 16/19] Update build/Program.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- build/Program.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build/Program.cs b/build/Program.cs index f88c67d9..daf46061 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -243,7 +243,11 @@ static async Task<(string version, bool isPrerelease)> GetVersion() // Increment minor version for next release var nextVersion = new Version(lastVersion.Major, lastVersion.Minor + 1, 0); - var commitCount = (await GetGitOutput("rev-list", "--count HEAD")).Trim(); + // Use commit count since the last version tag if available; otherwise, fall back to total count + var revListArgs = allTags.Any() + ? $"--count {lastTag}..HEAD" + : "--count HEAD"; + var commitCount = (await GetGitOutput("rev-list", revListArgs)).Trim(); var version = $"{nextVersion}-beta.{commitCount}"; Console.WriteLine($"Building prerelease version: {version}"); From 7afa468e159e49159be3cbd99276a79d4ad8c71c Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sat, 3 Jan 2026 13:29:29 +0000 Subject: [PATCH 17/19] Update build/Program.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- build/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Program.cs b/build/Program.cs index daf46061..3ab6055e 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -265,6 +265,6 @@ static async Task GetGitOutput(string command, string args) } catch (Exception ex) { - throw new Exception($"Git command failed: git {command} {args}\n{ex.Message}"); + throw new Exception($"Git command failed: git {command} {args}\n{ex.Message}", ex); } } From b2f2ea65ba4bd849762bd30d3a9988199ea42680 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sat, 3 Jan 2026 13:31:15 +0000 Subject: [PATCH 18/19] fmt --- build/Program.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build/Program.cs b/build/Program.cs index 3ab6055e..47a86745 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -244,9 +244,7 @@ static async Task<(string version, bool isPrerelease)> GetVersion() var nextVersion = new Version(lastVersion.Major, lastVersion.Minor + 1, 0); // Use commit count since the last version tag if available; otherwise, fall back to total count - var revListArgs = allTags.Any() - ? $"--count {lastTag}..HEAD" - : "--count HEAD"; + var revListArgs = allTags.Any() ? $"--count {lastTag}..HEAD" : "--count HEAD"; var commitCount = (await GetGitOutput("rev-list", revListArgs)).Trim(); var version = $"{nextVersion}-beta.{commitCount}"; From 5d47bfaeb6445264ed414ef73ba505c13464bc2c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 13:36:19 +0000 Subject: [PATCH 19/19] Add tag push trigger to workflow - Workflow now triggers on tag pushes in addition to branch pushes - Tags must match pattern: [0-9]+.[0-9]+.[0-9]+ (e.g., 0.43.0) - Updated documentation to explain both triggering methods - Allows publishing by pushing tags directly without requiring branch push Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .github/workflows/NUGET_RELEASE.md | 25 ++++++++++++++++++++----- .github/workflows/nuget-release.yml | 2 ++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.github/workflows/NUGET_RELEASE.md b/.github/workflows/NUGET_RELEASE.md index 8fa18710..42375089 100644 --- a/.github/workflows/NUGET_RELEASE.md +++ b/.github/workflows/NUGET_RELEASE.md @@ -4,7 +4,11 @@ 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 `master` or `release` branch. The workflow runs on both Windows and Ubuntu, but only the Windows build publishes to NuGet. +The `nuget-release.yml` workflow automatically builds, tests, and publishes SharpCompress packages to NuGet.org when: +- Changes are pushed to the `master` or `release` branch +- A version tag (format: `MAJOR.MINOR.PATCH`) is pushed + +The workflow runs on both Windows and Ubuntu, but only the Windows build publishes to NuGet. ## How It Works @@ -60,16 +64,27 @@ Consider enabling branch protection rules for the `release` branch to ensure: ### Creating a Stable Release -1. Ensure all changes are merged and tested on the `master` or `release` branch +There are two ways to trigger a stable release: + +**Method 1: Push tag to trigger workflow** +1. Ensure all changes are committed on the `master` or `release` branch 2. Create and push a version tag: ```bash git checkout master # or release git tag 0.43.0 git push origin 0.43.0 ``` -3. The workflow will automatically: - - Build and test the project on both Windows and Ubuntu - - Publish `SharpCompress 0.43.0` to NuGet.org (Windows build) +3. The workflow will automatically trigger, build, test, and publish `SharpCompress 0.43.0` to NuGet.org (Windows build) + +**Method 2: Tag after pushing to branch** +1. Ensure all changes are merged and pushed to the `master` or `release` branch +2. Create and push a version tag on the already-pushed commit: + ```bash + git checkout master # or release + git tag 0.43.0 + git push origin 0.43.0 + ``` +3. The workflow will automatically trigger, build, test, and publish `SharpCompress 0.43.0` to NuGet.org (Windows build) ### Creating a Prerelease diff --git a/.github/workflows/nuget-release.yml b/.github/workflows/nuget-release.yml index f1cb8f73..fe7d404a 100644 --- a/.github/workflows/nuget-release.yml +++ b/.github/workflows/nuget-release.yml @@ -5,6 +5,8 @@ on: branches: - 'master' - 'release' + tags: + - '[0-9]+.[0-9]+.[0-9]+' permissions: contents: read