From 754e63ecc0f4d84cdd24bde448c8ec4bca6f3944 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sat, 29 Aug 2026 14:20:47 -0400 Subject: [PATCH 1/2] Modernize CI/CD: GitHub Actions + MinVer, prep trunk-based branching Replaces the AppVeyor pipeline with GitHub Actions and adopts MinVer for fully automatic, git-tag-based versioning: - .github/workflows/ci.yml: build/test/coverage on PRs and pushes to main (Codecov upload), the required status check for branch protection once main is live. - .github/workflows/release.yml: on every push to main, packs and publishes a NuGet package (prerelease unless HEAD is an exact vX.Y.Z tag, per MinVer); on a vX.Y.Z tag push, also creates a GitHub Release with auto-generated notes. - src/ArgSentry/ArgSentry.csproj: added MinVer package reference and config (tag prefix "v", preview.0 prerelease identifier), removed the placeholder AssemblyVersion/FileVersion/InformationalVersion properties that AppVeyor used to patch by hand. - CONTRIBUTING.md: documents the new trunk-based flow (feature branch -> PR -> main), automatic prerelease publishing, and the tag-to-release process. - README.md: swapped the AppVeyor badge for a GitHub Actions CI badge; repointed the Codecov badge from master to main. appveyor.yml is left in place for now and will be removed once this pipeline is proven out on main, per the migration plan (dev/master are still the live branches at this commit). --- .github/workflows/ci.yml | 45 ++++++++++++++++++++++++++++++ .github/workflows/release.yml | 50 ++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 33 ++++++++++++++++++++++ README.md | 4 +-- src/ArgSentry/ArgSentry.csproj | 15 +++++++--- 5 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 CONTRIBUTING.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d66a3aa --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,45 @@ +name: CI + +on: + pull_request: + branches: [main] + push: + branches: [main] + +permissions: + contents: read + +jobs: + build-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # MinVer needs full history and tags + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 8.0.x + + - name: Restore + run: dotnet restore ArgSentry.sln + + - name: Build + run: dotnet build ArgSentry.sln --configuration Release --no-restore + + - name: Test with coverage + run: > + dotnet test test/ArgSentry.Test/ArgSentry.Test.csproj + --configuration Release --no-build + /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + /p:CoverletOutput=./coverage/ + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + files: test/ArgSentry.Test/coverage/coverage.opencover.xml + fail_ci_if_error: false + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..747f8db --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,50 @@ +name: Release + +on: + push: + branches: [main] + tags: ['v*.*.*'] + +permissions: + contents: write # needed to create GitHub Releases on tag pushes + +jobs: + pack-publish: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # MinVer needs full history and tags + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 8.0.x + + - name: Restore + run: dotnet restore ArgSentry.sln + + - name: Build + run: dotnet build src/ArgSentry/ArgSentry.csproj --configuration Release --no-restore + + - name: Pack + run: > + dotnet pack src/ArgSentry/ArgSentry.csproj + --configuration Release --no-build + --output ./dist + + - name: Push to NuGet + run: > + dotnet nuget push "./dist/*.nupkg" + --api-key ${{ secrets.NUGET_API_KEY }} + --source https://api.nuget.org/v3/index.json + --skip-duplicate + + - name: Create GitHub Release + if: startsWith(github.ref, 'refs/tags/v') + uses: softprops/action-gh-release@v2 + with: + generate_release_notes: true + files: ./dist/*.nupkg diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4f416b0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,33 @@ +# Contributing + +## Branching and Pull Requests + +This project uses a trunk-based development model. `main` is the only long-lived branch. + +1. Create a short-lived feature branch off `main`. +2. Open a Pull Request targeting `main`. +3. The `CI` workflow (`build-test` job) must pass. +4. Merges must result in linear history. Use squash or rebase merges. + +## Releases + +Releases are fully automated. + +* **Prereleases:** Every merge to `main` triggers the `release.yml` workflow, which publishes a prerelease NuGet package (e.g., `3.1.0-preview.0.7`). No action is required from contributors. +* **Stable Releases:** The maintainer cuts stable releases by pushing an annotated git tag matching `vX.Y.Z` (e.g. `git tag -a v3.1.0 -m "v3.1.0" && git push origin v3.1.0`). This builds a clean `X.Y.Z` package, publishes it to NuGet, and creates a GitHub Release with auto-generated notes. + +## Versioning + +Versioning is handled automatically via [MinVer](https://github.com/adamralph/minver) based on git tags. + +* Do not manually edit `AssemblyVersion`, `FileVersion`, or `InformationalVersion` in the `.csproj` file. +* Version numbers are derived from the latest git tag. + +## Local Development + +To build and test the project locally: + +```bash +dotnet build +dotnet test +``` diff --git a/README.md b/README.md index b76d436..5b13b12 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ ArgSentry ![Nuget](https://img.shields.io/nuget/v/argsentry) ![Nuget](https://img.shields.io/nuget/dt/argsentry) -[![Build status](https://ci.appveyor.com/api/projects/status/yxa3tt4d9exdhgik?svg=true)](https://ci.appveyor.com/project/eric-davis/argsentry) -[![codecov](https://codecov.io/gh/eric-davis/ArgSentry/branch/master/graph/badge.svg)](https://codecov.io/gh/eric-davis/ArgSentry) +[![CI](https://github.com/eric-davis/ArgSentry/actions/workflows/ci.yml/badge.svg)](https://github.com/eric-davis/ArgSentry/actions/workflows/ci.yml) +[![codecov](https://codecov.io/gh/eric-davis/ArgSentry/branch/main/graph/badge.svg)](https://codecov.io/gh/eric-davis/ArgSentry) ArgSentry is a .NET / .NET Core utility library for validating method argument values. diff --git a/src/ArgSentry/ArgSentry.csproj b/src/ArgSentry/ArgSentry.csproj index 2c3f1f3..6c3ce7e 100644 --- a/src/ArgSentry/ArgSentry.csproj +++ b/src/ArgSentry/ArgSentry.csproj @@ -18,10 +18,10 @@ netstandard1.1 - - 1.0.0.0 - 1.0.0.0 - 1.0.0.0 + + v + preview.0 + normal ArgSentry ArgSentry is a utility class for validating method argument values. @@ -52,4 +52,11 @@ + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + From 6f0b8457f60b7504a9332b57eb9b92090475c8a2 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sat, 29 Aug 2026 14:21:38 -0400 Subject: [PATCH 2/2] ci: run pull_request checks regardless of base branch The pull_request trigger was scoped to branches:[main], but main doesn't exist yet (this repo still targets PRs at dev pending the branch rename) - so CI was silently not running on PRs. Since this is a trunk-based setup, every PR will target main once the rename is done anyway, so dropping the branch filter is correct long-term too. --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d66a3aa..c383bb2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,6 @@ name: CI on: pull_request: - branches: [main] push: branches: [main]