diff --git a/.github/BuildHelpers/BuildHelpers.csproj b/.github/BuildHelpers/BuildHelpers.csproj new file mode 100644 index 0000000..eab728f --- /dev/null +++ b/.github/BuildHelpers/BuildHelpers.csproj @@ -0,0 +1,14 @@ + + + + net10.0 + enable + enable + + + + + + + + diff --git a/.github/BuildHelpers/Targets.cs b/.github/BuildHelpers/Targets.cs new file mode 100644 index 0000000..d0afdad --- /dev/null +++ b/.github/BuildHelpers/Targets.cs @@ -0,0 +1,92 @@ +using static Bullseye.Targets; +using static SimpleExec.Command; + +namespace BuildHelpers; + +/// +/// Registers build targets for per-lib build scripts. +/// +public static class Targets +{ + private static readonly Lazy RepoRoot = new(FindRoot); + + public const string Restore = "restore"; + public const string Build = "build"; + public const string Clean = "clean"; + public const string Pack = "pack"; + public const string Test = "test"; + + private const string Default = "default"; + + /// + /// Registers all shared targets parameterized by the lib's solution filter path. + /// + /// + /// Repo-relative path to the lib's solution filter + /// (e.g. signatures/signatures.slnf). + /// + /// + /// Repo-relative path to the lib's packable src project + /// (e.g. signatures/src/Http.HttpSignatures). + /// + public static void SharedTargets(string slnfPath, string packProjectPath) + { + ArgumentNullException.ThrowIfNull(slnfPath); + ArgumentNullException.ThrowIfNull(packProjectPath); + + var libDir = slnfPath.Split('/')[0]; + + Target(Restore, () => + RunAsync("dotnet", $"restore {slnfPath}", RepoRoot.Value)); + + Target(Build, dependsOn: [Restore], () => + RunAsync("dotnet", $"build {slnfPath} --no-restore -c Release", RepoRoot.Value)); + + Target(Clean, () => + RunAsync("dotnet", $"clean {slnfPath}", RepoRoot.Value)); + + Target(Pack, dependsOn: [Build], () => + RunAsync( + "dotnet", + $"pack {packProjectPath} --no-build -c Release -o {libDir}/artifacts", + RepoRoot.Value)); + } + + /// + /// Registers a test target that runs dotnet test on a test project with standard options. + /// + /// The target name (e.g. "test"). + /// + /// Repo-relative path to the test project + /// (e.g. "signatures/test/Http.HttpSignatures.Tests"). + /// + public static void TestTarget(string targetName, string testProjectPath) => + Target(targetName, dependsOn: [Restore], () => + RunAsync( + "dotnet", + $"test --project {testProjectPath} -c Release --no-restore --report-xunit-trx " + + $"--report-xunit-trx-filename {testProjectPath.Replace('/', '-')}-tests.trx", + RepoRoot.Value)); + + public static void DefaultTarget(IEnumerable dependsOn) => + Target(Default, dependsOn); + + public static Task RunTargetsAndExitAsync(IEnumerable args) => + Bullseye.Targets.RunTargetsAndExitAsync(args, messageOnly: ex => ex is SimpleExec.ExitCodeException); + + private static string FindRoot() + { + var root = Directory.GetCurrentDirectory(); + + // Repositories have a .git folder, worktrees have a .git file, so check for both. + while (!Directory.Exists(Path.Combine(root, ".git")) && !File.Exists(Path.Combine(root, ".git"))) + { + root = Directory.GetParent(root) is { } parent + ? parent.FullName + : throw new InvalidOperationException( + "Could not find repository root (no .git directory or file found)"); + } + + return root; + } +} diff --git a/.github/workflows/ci-template.yml b/.github/workflows/ci-template.yml new file mode 100644 index 0000000..2154284 --- /dev/null +++ b/.github/workflows/ci-template.yml @@ -0,0 +1,71 @@ +name: ci-template + +on: + workflow_call: + inputs: + product: + description: "Lib folder name (e.g. signatures, structured-field-values)" + required: true + type: string + test-targets: + description: 'JSON array of build.cs test targets (e.g. ["test"]). Empty array or "[]" to skip.' + required: false + type: string + default: '["test"]' + os-matrix: + description: 'JSON array of OS runners for the test job. Defaults to ubuntu only.' + required: false + type: string + default: '["ubuntu-latest"]' + +env: + DOTNET_NOLOGO: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + +jobs: + build: + name: Build + runs-on: ubuntu-latest + permissions: + contents: read + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + - name: Build + run: dotnet run ${{ inputs.product }}/build.cs -- build + + test: + name: "Test: ${{ matrix.target }} (${{ matrix.os }})" + if: inputs.test-targets != '[]' + runs-on: ${{ matrix.os }} + permissions: + contents: read + strategy: + matrix: + target: ${{ fromJson(inputs.test-targets) }} + os: ${{ fromJson(inputs.os-matrix) }} + fail-fast: false + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + - name: Test + run: dotnet run ${{ inputs.product }}/build.cs -- ${{ matrix.target }} + - name: Test report + if: success() || failure() + uses: phoenix-actions/test-reporting@f957cd93fc2d848d556fa0d03c57bc79127b6b5e + with: + name: "${{ inputs.product }}: ${{ matrix.target }} (${{ matrix.os }})" + path: "**/*-tests.trx" + reporter: dotnet-trx + output-to: step-summary + fail-on-error: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 6c1494e..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,108 +0,0 @@ -name: ci - -on: - push: - branches: - - main - - '**' - pull_request: - workflow_dispatch: - -jobs: - build-and-test: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: '10.0.x' - - - name: Restore dependencies - run: dotnet restore http-lib.slnx - - - name: Build - run: dotnet build http-lib.slnx --no-restore --configuration Release - - - name: Run tests - run: | - dotnet run --project structured-field-values/test/Http.StructuredFieldValues.Tests/Http.StructuredFieldValues.Tests.csproj --no-build --configuration Release - dotnet run --project signatures/test/Http.HttpSignatures.Tests/Http.HttpSignatures.Tests.csproj --no-build --configuration Release - dotnet run --project hybrid-cache-handler/test/HttpHybridCacheHandler.Tests/HttpHybridCacheHandler.Tests.csproj --no-build --configuration Release - dotnet run --project file-distributed-cache/test/FileDistributedCache.Tests/FileDistributedCache.Tests.csproj --no-build --configuration Release - - - name: Run benchmarks - run: | - cd hybrid-cache-handler/benchmarks/Benchmarks - dotnet run --project Benchmarks.csproj --configuration Release --no-build -- --exporters json - continue-on-error: true - - - name: Add benchmark results to summary - if: always() - run: | - echo "## Benchmark Results" >> $GITHUB_STEP_SUMMARY - if [ -f "hybrid-cache-handler/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks-report.json" ]; then - echo "Benchmark completed successfully. Full results available in artifacts." >> $GITHUB_STEP_SUMMARY - else - echo "Benchmark execution completed with warnings or errors." >> $GITHUB_STEP_SUMMARY - fi - - - name: Upload benchmark results - if: always() - uses: actions/upload-artifact@v4 - with: - name: benchmark-results - path: hybrid-cache-handler/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/ - if-no-files-found: ignore - - - name: Build NuGet packages - run: | - dotnet pack structured-field-values/src/Http.StructuredFieldValues/Http.StructuredFieldValues.csproj --no-build --configuration Release --output ./packages - dotnet pack signatures/src/Http.HttpSignatures/Http.HttpSignatures.csproj --no-build --configuration Release --output ./packages - dotnet pack hybrid-cache-handler/src/HttpHybridCacheHandler/HttpHybridCacheHandler.csproj --no-build --configuration Release --output ./packages - dotnet pack file-distributed-cache/src/FileDistributedCache/FileDistributedCache.csproj --no-build --configuration Release --output ./packages - - - name: Upload NuGet packages - uses: actions/upload-artifact@v4 - with: - name: nuget-packages - path: ./packages/*.nupkg - - - name: Add build summary - if: always() - run: | - echo "## Build Summary" >> $GITHUB_STEP_SUMMARY - echo "✅ Build completed" >> $GITHUB_STEP_SUMMARY - echo "✅ Tests executed" >> $GITHUB_STEP_SUMMARY - echo "✅ NuGet packages created" >> $GITHUB_STEP_SUMMARY - - cache-conformance: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: '10.0.x' - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' - - - name: Run RFC 9111 conformance suite - run: ./hybrid-cache-handler/conformance/run-conformance.sh - - - name: Upload conformance results - if: always() - uses: actions/upload-artifact@v4 - with: - name: cache-conformance-results - path: hybrid-cache-handler/conformance/results.json - if-no-files-found: ignore diff --git a/.github/workflows/file-distributed-cache-ci.yml b/.github/workflows/file-distributed-cache-ci.yml new file mode 100644 index 0000000..fc2a059 --- /dev/null +++ b/.github/workflows/file-distributed-cache-ci.yml @@ -0,0 +1,34 @@ +name: file-distributed-cache/ci + +on: + workflow_dispatch: + push: + branches: + - main + - '**' + paths: + - .github/BuildHelpers/** + - .github/workflows/file-distributed-cache-ci.yml + - .github/workflows/ci-template.yml + - file-distributed-cache/** + - .editorconfig + - Directory.Build.props + - global.json + - http-lib.slnx + pull_request: + paths: + - .github/BuildHelpers/** + - .github/workflows/file-distributed-cache-ci.yml + - .github/workflows/ci-template.yml + - file-distributed-cache/** + - .editorconfig + - Directory.Build.props + - global.json + - http-lib.slnx + +jobs: + build: + uses: ./.github/workflows/ci-template.yml + with: + product: file-distributed-cache + test-targets: '["test"]' diff --git a/.github/workflows/file-distributed-cache-release.yml b/.github/workflows/file-distributed-cache-release.yml new file mode 100644 index 0000000..2f3088d --- /dev/null +++ b/.github/workflows/file-distributed-cache-release.yml @@ -0,0 +1,20 @@ +name: file-distributed-cache/release + +on: + workflow_dispatch: + inputs: + version: + description: 'Version number (x.y.z or x.y.z-prerelease.1)' + required: true + type: string + +jobs: + release: + uses: ./.github/workflows/release-template.yml + with: + product: file-distributed-cache + package: DamianH.FileDistributedCache + tag-prefix: fdc-v + version: ${{ inputs.version }} + secrets: + NUGET_ORG_APIKEY: ${{ secrets.NUGET_ORG_APIKEY }} diff --git a/.github/workflows/hybrid-cache-handler-checks.yml b/.github/workflows/hybrid-cache-handler-checks.yml new file mode 100644 index 0000000..f9bf7dc --- /dev/null +++ b/.github/workflows/hybrid-cache-handler-checks.yml @@ -0,0 +1,94 @@ +name: hybrid-cache-handler/checks + +on: + workflow_dispatch: + push: + branches: + - main + - '**' + paths: + - .github/workflows/hybrid-cache-handler-checks.yml + - hybrid-cache-handler/** + - Directory.Build.props + - global.json + - http-lib.slnx + pull_request: + paths: + - .github/workflows/hybrid-cache-handler-checks.yml + - hybrid-cache-handler/** + - Directory.Build.props + - global.json + - http-lib.slnx + +env: + DOTNET_NOLOGO: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + +jobs: + benchmarks: + name: Benchmarks + runs-on: ubuntu-latest + permissions: + contents: read + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + + - name: Run benchmarks + run: | + cd hybrid-cache-handler/benchmarks/Benchmarks + dotnet run --project Benchmarks.csproj --configuration Release -- --exporters json + continue-on-error: true + + - name: Add benchmark results to summary + if: always() + run: | + echo "## Benchmark Results" >> $GITHUB_STEP_SUMMARY + if [ -f "hybrid-cache-handler/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks-report.json" ]; then + echo "Benchmark completed successfully. Full results available in artifacts." >> $GITHUB_STEP_SUMMARY + else + echo "Benchmark execution completed with warnings or errors." >> $GITHUB_STEP_SUMMARY + fi + + - name: Upload benchmark results + if: always() + uses: actions/upload-artifact@v4 + with: + name: benchmark-results + path: hybrid-cache-handler/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/ + if-no-files-found: ignore + + cache-conformance: + name: RFC 9111 conformance + runs-on: ubuntu-latest + permissions: + contents: read + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Run RFC 9111 conformance suite + run: ./hybrid-cache-handler/conformance/run-conformance.sh + + - name: Upload conformance results + if: always() + uses: actions/upload-artifact@v4 + with: + name: cache-conformance-results + path: hybrid-cache-handler/conformance/results.json + if-no-files-found: ignore diff --git a/.github/workflows/hybrid-cache-handler-ci.yml b/.github/workflows/hybrid-cache-handler-ci.yml new file mode 100644 index 0000000..40aecaa --- /dev/null +++ b/.github/workflows/hybrid-cache-handler-ci.yml @@ -0,0 +1,34 @@ +name: hybrid-cache-handler/ci + +on: + workflow_dispatch: + push: + branches: + - main + - '**' + paths: + - .github/BuildHelpers/** + - .github/workflows/hybrid-cache-handler-ci.yml + - .github/workflows/ci-template.yml + - hybrid-cache-handler/** + - .editorconfig + - Directory.Build.props + - global.json + - http-lib.slnx + pull_request: + paths: + - .github/BuildHelpers/** + - .github/workflows/hybrid-cache-handler-ci.yml + - .github/workflows/ci-template.yml + - hybrid-cache-handler/** + - .editorconfig + - Directory.Build.props + - global.json + - http-lib.slnx + +jobs: + build: + uses: ./.github/workflows/ci-template.yml + with: + product: hybrid-cache-handler + test-targets: '["test"]' diff --git a/.github/workflows/hybrid-cache-handler-release.yml b/.github/workflows/hybrid-cache-handler-release.yml new file mode 100644 index 0000000..d7d73e4 --- /dev/null +++ b/.github/workflows/hybrid-cache-handler-release.yml @@ -0,0 +1,20 @@ +name: hybrid-cache-handler/release + +on: + workflow_dispatch: + inputs: + version: + description: 'Version number (x.y.z or x.y.z-prerelease.1)' + required: true + type: string + +jobs: + release: + uses: ./.github/workflows/release-template.yml + with: + product: hybrid-cache-handler + package: DamianH.HttpHybridCacheHandler + tag-prefix: cache-v + version: ${{ inputs.version }} + secrets: + NUGET_ORG_APIKEY: ${{ secrets.NUGET_ORG_APIKEY }} diff --git a/.github/workflows/release-template.yml b/.github/workflows/release-template.yml new file mode 100644 index 0000000..dbe48ec --- /dev/null +++ b/.github/workflows/release-template.yml @@ -0,0 +1,93 @@ +name: release-template + +on: + workflow_call: + inputs: + product: + description: "Lib folder name (e.g. signatures)" + required: true + type: string + package: + description: "NuGet package ID (e.g. DamianH.Http.HttpSignatures)" + required: true + type: string + tag-prefix: + description: "Git tag prefix (e.g. sig-v)" + required: true + type: string + version: + description: "Version number (x.y.z or x.y.z-prerelease.1)" + required: true + type: string + secrets: + NUGET_ORG_APIKEY: + required: true + +env: + DOTNET_NOLOGO: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + +jobs: + release: + name: Release + runs-on: ubuntu-latest + environment: nuget.org + permissions: + contents: write + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + + - name: Validate version format + run: | + if ! echo "${{ inputs.version }}" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+\.[0-9]+)?$'; then + echo "Invalid version format. Expected: x.y.z or x.y.z-prerelease.1" + exit 1 + fi + + - name: Remove existing tag if present + run: | + TAG="${{ inputs.tag-prefix }}${{ inputs.version }}" + if git rev-parse "$TAG" >/dev/null 2>&1; then + echo "Tag $TAG exists, removing it" + git tag -d "$TAG" + git push origin ":refs/tags/$TAG" || true + fi + + - name: Create and push tag + run: | + TAG="${{ inputs.tag-prefix }}${{ inputs.version }}" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "$TAG" -m "Release ${{ inputs.package }} ${{ inputs.version }}" + git push origin "$TAG" + + - name: Pack NuGet package + # Runs after tagging so MinVer derives the package version from the new tag. + run: dotnet run ${{ inputs.product }}/build.cs -- pack + + - name: Push to NuGet.org + run: | + dotnet nuget push "${{ inputs.product }}/artifacts/*.nupkg" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_ORG_APIKEY }} --skip-duplicate + + - name: Upload packages as artifacts + uses: actions/upload-artifact@v4 + with: + name: nuget-packages-${{ inputs.package }}-${{ inputs.version }} + path: ${{ inputs.product }}/artifacts/*.nupkg + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ inputs.tag-prefix }}${{ inputs.version }} + name: ${{ inputs.package }} ${{ inputs.version }} + draft: false + prerelease: ${{ contains(inputs.version, '-') }} + generate_release_notes: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index a02e0b8..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,110 +0,0 @@ -name: release - -on: - workflow_dispatch: - inputs: - package: - description: 'Package to release' - required: true - type: choice - options: - - DamianH.Http.StructuredFieldValues - - DamianH.Http.HttpSignatures - - DamianH.HttpHybridCacheHandler - - DamianH.FileDistributedCache - version: - description: 'Version number (x.y.z or x.y.z-prerelease.1)' - required: true - type: string - -jobs: - release: - runs-on: ubuntu-latest - environment: nuget.org - permissions: - contents: write - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: '10.0.x' - - - name: Determine tag prefix and project path - id: package-info - run: | - case "${{ inputs.package }}" in - "DamianH.Http.StructuredFieldValues") - echo "tag_prefix=sfv-v" >> $GITHUB_OUTPUT - echo "project_path=structured-field-values/src/Http.StructuredFieldValues/Http.StructuredFieldValues.csproj" >> $GITHUB_OUTPUT - ;; - "DamianH.Http.HttpSignatures") - echo "tag_prefix=sig-v" >> $GITHUB_OUTPUT - echo "project_path=signatures/src/Http.HttpSignatures/Http.HttpSignatures.csproj" >> $GITHUB_OUTPUT - ;; - "DamianH.HttpHybridCacheHandler") - echo "tag_prefix=cache-v" >> $GITHUB_OUTPUT - echo "project_path=hybrid-cache-handler/src/HttpHybridCacheHandler/HttpHybridCacheHandler.csproj" >> $GITHUB_OUTPUT - ;; - "DamianH.FileDistributedCache") - echo "tag_prefix=fdc-v" >> $GITHUB_OUTPUT - echo "project_path=file-distributed-cache/src/FileDistributedCache/FileDistributedCache.csproj" >> $GITHUB_OUTPUT - ;; - esac - - - name: Validate version format - run: | - if ! echo "${{ inputs.version }}" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+\.[0-9]+)?$'; then - echo "Invalid version format. Expected: x.y.z or x.y.z-prerelease.1" - exit 1 - fi - - - name: Remove existing tag if present - run: | - TAG="${{ steps.package-info.outputs.tag_prefix }}${{ inputs.version }}" - if git rev-parse "$TAG" >/dev/null 2>&1; then - echo "Tag $TAG exists, removing it" - git tag -d "$TAG" - git push origin ":refs/tags/$TAG" || true - fi - - - name: Create and push tag - run: | - TAG="${{ steps.package-info.outputs.tag_prefix }}${{ inputs.version }}" - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git tag -a "$TAG" -m "Release ${{ inputs.package }} ${{ inputs.version }}" - git push origin "$TAG" - - - name: Restore dependencies - run: dotnet restore http-lib.slnx - - - name: Build - run: dotnet build http-lib.slnx --configuration Release --no-restore - - - name: Pack NuGet package - run: | - dotnet pack ${{ steps.package-info.outputs.project_path }} --configuration Release --no-build --output ./packages - - - name: Push to NuGet.org - run: | - dotnet nuget push "./packages/*.nupkg" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_ORG_APIKEY }} --skip-duplicate - - - name: Upload packages as artifacts - uses: actions/upload-artifact@v4 - with: - name: nuget-packages-${{ inputs.package }}-${{ inputs.version }} - path: ./packages/*.nupkg - - - name: Create GitHub Release - uses: softprops/action-gh-release@v2 - with: - tag_name: ${{ steps.package-info.outputs.tag_prefix }}${{ inputs.version }} - name: ${{ inputs.package }} ${{ inputs.version }} - draft: false - prerelease: ${{ contains(inputs.version, '-') }} - generate_release_notes: true diff --git a/.github/workflows/signatures-ci.yml b/.github/workflows/signatures-ci.yml new file mode 100644 index 0000000..d3e8702 --- /dev/null +++ b/.github/workflows/signatures-ci.yml @@ -0,0 +1,34 @@ +name: signatures/ci + +on: + workflow_dispatch: + push: + branches: + - main + - '**' + paths: + - .github/BuildHelpers/** + - .github/workflows/signatures-ci.yml + - .github/workflows/ci-template.yml + - signatures/** + - .editorconfig + - Directory.Build.props + - global.json + - http-lib.slnx + pull_request: + paths: + - .github/BuildHelpers/** + - .github/workflows/signatures-ci.yml + - .github/workflows/ci-template.yml + - signatures/** + - .editorconfig + - Directory.Build.props + - global.json + - http-lib.slnx + +jobs: + build: + uses: ./.github/workflows/ci-template.yml + with: + product: signatures + test-targets: '["test"]' diff --git a/.github/workflows/signatures-release.yml b/.github/workflows/signatures-release.yml new file mode 100644 index 0000000..7fe5400 --- /dev/null +++ b/.github/workflows/signatures-release.yml @@ -0,0 +1,20 @@ +name: signatures/release + +on: + workflow_dispatch: + inputs: + version: + description: 'Version number (x.y.z or x.y.z-prerelease.1)' + required: true + type: string + +jobs: + release: + uses: ./.github/workflows/release-template.yml + with: + product: signatures + package: DamianH.Http.HttpSignatures + tag-prefix: sig-v + version: ${{ inputs.version }} + secrets: + NUGET_ORG_APIKEY: ${{ secrets.NUGET_ORG_APIKEY }} diff --git a/.github/workflows/structured-field-values-ci.yml b/.github/workflows/structured-field-values-ci.yml new file mode 100644 index 0000000..2370bfb --- /dev/null +++ b/.github/workflows/structured-field-values-ci.yml @@ -0,0 +1,34 @@ +name: structured-field-values/ci + +on: + workflow_dispatch: + push: + branches: + - main + - '**' + paths: + - .github/BuildHelpers/** + - .github/workflows/structured-field-values-ci.yml + - .github/workflows/ci-template.yml + - structured-field-values/** + - .editorconfig + - Directory.Build.props + - global.json + - http-lib.slnx + pull_request: + paths: + - .github/BuildHelpers/** + - .github/workflows/structured-field-values-ci.yml + - .github/workflows/ci-template.yml + - structured-field-values/** + - .editorconfig + - Directory.Build.props + - global.json + - http-lib.slnx + +jobs: + build: + uses: ./.github/workflows/ci-template.yml + with: + product: structured-field-values + test-targets: '["test"]' diff --git a/.github/workflows/structured-field-values-release.yml b/.github/workflows/structured-field-values-release.yml new file mode 100644 index 0000000..4fbf4ef --- /dev/null +++ b/.github/workflows/structured-field-values-release.yml @@ -0,0 +1,20 @@ +name: structured-field-values/release + +on: + workflow_dispatch: + inputs: + version: + description: 'Version number (x.y.z or x.y.z-prerelease.1)' + required: true + type: string + +jobs: + release: + uses: ./.github/workflows/release-template.yml + with: + product: structured-field-values + package: DamianH.Http.StructuredFieldValues + tag-prefix: sfv-v + version: ${{ inputs.version }} + secrets: + NUGET_ORG_APIKEY: ${{ secrets.NUGET_ORG_APIKEY }} diff --git a/README.md b/README.md index 4c3ed41..1ca1972 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # http-libs -[![CI](https://github.com/damianh/http-hybridcache-handler/actions/workflows/ci.yml/badge.svg)](https://github.com/damianh/http-hybridcache-handler/actions/workflows/ci.yml) +[![CI](https://github.com/damianh/http-libs/actions/workflows/hybrid-cache-handler-ci.yml/badge.svg)](https://github.com/damianh/http-libs/actions) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![.NET](https://img.shields.io/badge/.NET-10.0-purple.svg)](https://dotnet.microsoft.com/) -[![GitHub Stars](https://img.shields.io/github/stars/damianh/http-hybridcache-handler.svg)](https://github.com/damianh/http-hybridcache-handler/stargazers) +[![GitHub Stars](https://img.shields.io/github/stars/damianh/http-libs.svg)](https://github.com/damianh/http-libs/stargazers) A collection of .NET libraries for HTTP caching, structured field values, and message signatures. @@ -30,14 +30,18 @@ signatures/ # RFC 9421 HTTP message signatures ## Building +Each lib has its own build script and solution filter: + ```bash -dotnet build http-lib.slnx +dotnet run signatures/build.cs -- build # or: structured-field-values, hybrid-cache-handler, file-distributed-cache +dotnet build http-lib.slnx # everything ``` ## Running Tests ```bash -dotnet test http-lib.slnx +dotnet run signatures/build.cs -- test # per lib +dotnet test http-lib.slnx # everything ``` ## License diff --git a/file-distributed-cache/build.cs b/file-distributed-cache/build.cs new file mode 100644 index 0000000..ddcd22c --- /dev/null +++ b/file-distributed-cache/build.cs @@ -0,0 +1,17 @@ +#:project ../.github/BuildHelpers/BuildHelpers.csproj + +using static BuildHelpers.Targets; + +SharedTargets( + "file-distributed-cache/file-distributed-cache.slnf", + "file-distributed-cache/src/FileDistributedCache"); + +TestTarget(Test, "file-distributed-cache/test/FileDistributedCache.Tests"); + +DefaultTarget(dependsOn: +[ + Build, + Test, +]); + +await RunTargetsAndExitAsync(args); diff --git a/file-distributed-cache/file-distributed-cache.slnf b/file-distributed-cache/file-distributed-cache.slnf new file mode 100644 index 0000000..a78dbfb --- /dev/null +++ b/file-distributed-cache/file-distributed-cache.slnf @@ -0,0 +1,10 @@ +{ + "solution": { + "path": "..\\http-lib.slnx", + "projects": [ + "file-distributed-cache\\src\\FileDistributedCache\\FileDistributedCache.csproj", + "file-distributed-cache\\test\\FileDistributedCache.Tests\\FileDistributedCache.Tests.csproj", + "file-distributed-cache\\samples\\FileDistributedCacheSample\\FileDistributedCacheSample.csproj" + ] + } +} diff --git a/hybrid-cache-handler/build.cs b/hybrid-cache-handler/build.cs new file mode 100644 index 0000000..067771e --- /dev/null +++ b/hybrid-cache-handler/build.cs @@ -0,0 +1,17 @@ +#:project ../.github/BuildHelpers/BuildHelpers.csproj + +using static BuildHelpers.Targets; + +SharedTargets( + "hybrid-cache-handler/hybrid-cache-handler.slnf", + "hybrid-cache-handler/src/HttpHybridCacheHandler"); + +TestTarget(Test, "hybrid-cache-handler/test/HttpHybridCacheHandler.Tests"); + +DefaultTarget(dependsOn: +[ + Build, + Test, +]); + +await RunTargetsAndExitAsync(args); diff --git a/hybrid-cache-handler/hybrid-cache-handler.slnf b/hybrid-cache-handler/hybrid-cache-handler.slnf new file mode 100644 index 0000000..38c825e --- /dev/null +++ b/hybrid-cache-handler/hybrid-cache-handler.slnf @@ -0,0 +1,14 @@ +{ + "solution": { + "path": "..\\http-lib.slnx", + "projects": [ + "hybrid-cache-handler\\src\\HttpHybridCacheHandler\\HttpHybridCacheHandler.csproj", + "hybrid-cache-handler\\test\\HttpHybridCacheHandler.Tests\\HttpHybridCacheHandler.Tests.csproj", + "hybrid-cache-handler\\samples\\HttpClientFactorySample\\HttpClientFactorySample.csproj", + "hybrid-cache-handler\\samples\\FusionCacheSample\\FusionCacheSample.csproj", + "hybrid-cache-handler\\samples\\YarpCachingProxySample\\YarpCachingProxySample.csproj", + "hybrid-cache-handler\\benchmarks\\Benchmarks\\Benchmarks.csproj", + "hybrid-cache-handler\\conformance\\ConformanceProxy\\ConformanceProxy.csproj" + ] + } +} diff --git a/signatures/build.cs b/signatures/build.cs new file mode 100644 index 0000000..734c43e --- /dev/null +++ b/signatures/build.cs @@ -0,0 +1,17 @@ +#:project ../.github/BuildHelpers/BuildHelpers.csproj + +using static BuildHelpers.Targets; + +SharedTargets( + "signatures/signatures.slnf", + "signatures/src/Http.HttpSignatures"); + +TestTarget(Test, "signatures/test/Http.HttpSignatures.Tests"); + +DefaultTarget(dependsOn: +[ + Build, + Test, +]); + +await RunTargetsAndExitAsync(args); diff --git a/signatures/signatures.slnf b/signatures/signatures.slnf new file mode 100644 index 0000000..32d10be --- /dev/null +++ b/signatures/signatures.slnf @@ -0,0 +1,9 @@ +{ + "solution": { + "path": "..\\http-lib.slnx", + "projects": [ + "signatures\\src\\Http.HttpSignatures\\Http.HttpSignatures.csproj", + "signatures\\test\\Http.HttpSignatures.Tests\\Http.HttpSignatures.Tests.csproj" + ] + } +} diff --git a/structured-field-values/build.cs b/structured-field-values/build.cs new file mode 100644 index 0000000..929df2c --- /dev/null +++ b/structured-field-values/build.cs @@ -0,0 +1,17 @@ +#:project ../.github/BuildHelpers/BuildHelpers.csproj + +using static BuildHelpers.Targets; + +SharedTargets( + "structured-field-values/structured-field-values.slnf", + "structured-field-values/src/Http.StructuredFieldValues"); + +TestTarget(Test, "structured-field-values/test/Http.StructuredFieldValues.Tests"); + +DefaultTarget(dependsOn: +[ + Build, + Test, +]); + +await RunTargetsAndExitAsync(args); diff --git a/structured-field-values/structured-field-values.slnf b/structured-field-values/structured-field-values.slnf new file mode 100644 index 0000000..20ee3cf --- /dev/null +++ b/structured-field-values/structured-field-values.slnf @@ -0,0 +1,11 @@ +{ + "solution": { + "path": "..\\http-lib.slnx", + "projects": [ + "structured-field-values\\src\\Http.StructuredFieldValues\\Http.StructuredFieldValues.csproj", + "structured-field-values\\test\\Http.StructuredFieldValues.Tests\\Http.StructuredFieldValues.Tests.csproj", + "structured-field-values\\samples\\HttpClientSample\\HttpClientSample.csproj", + "structured-field-values\\samples\\AspNetCoreSample\\AspNetCoreSample.csproj" + ] + } +}