From f7c0548e14164e5e95d38dc5947a0e2d2568277e Mon Sep 17 00:00:00 2001 From: Robert McLaws <1657085+robertmclaws@users.noreply.github.com> Date: Sun, 5 Apr 2026 19:23:34 -0400 Subject: [PATCH 1/5] Add CI/CD workflows for NuGet publishing with Trusted Publishing Adapted from DotNetDocs build process for Breakdance solution. Uses OIDC-based NuGet Trusted Publishing for secure package deployment. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build-and-deploy.yml | 316 +++++++++++++++++++++++++ .github/workflows/pr-validation.yml | 100 ++++++++ 2 files changed, 416 insertions(+) create mode 100644 .github/workflows/build-and-deploy.yml create mode 100644 .github/workflows/pr-validation.yml diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml new file mode 100644 index 0000000..f6d11d8 --- /dev/null +++ b/.github/workflows/build-and-deploy.yml @@ -0,0 +1,316 @@ +name: Build and Deploy to NuGet + +on: + push: + branches: [ main, dev ] + paths-ignore: + - '.github/**' + - 'src/CloudNimble.Breakdance.Docs/**' + - 'specs/**' + workflow_dispatch: + inputs: + deploy_to_nuget: + description: 'Deploy to NuGet' + required: false + default: 'false' + type: choice + options: + - 'true' + - 'false' + +permissions: + contents: write + actions: write + id-token: write + +env: + DOTNET_VERSION: '10.0.x' + SOLUTION_FILE: 'src/CloudNimble.Breakdance.slnx' + +jobs: + build: + runs-on: windows-latest + outputs: + version: ${{ steps.version.outputs.VERSION }} + + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + fetch-depth: 0 # Full history for versioning + + - name: Install .NET versions + shell: pwsh + run: | + Write-Host "Installing .NET versions..." + $versions = @("8.0", "9.0", "10.0") + foreach ($version in $versions) { + Write-Host "Installing .NET $version..." + Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile "dotnet-install.ps1" + ./dotnet-install.ps1 -Channel $version -InstallDir "$env:ProgramFiles\dotnet" + } + + # Add to PATH for this job + echo "$env:ProgramFiles\dotnet" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + # Verify installation + dotnet --list-sdks + + - name: Get version variables + id: version + shell: pwsh + run: | + # Get version components from repository variables + $majorVersion = "${{ vars.VERSION_MAJOR }}" + if ([string]::IsNullOrEmpty($majorVersion)) { $majorVersion = "1" } + + $minorVersion = "${{ vars.VERSION_MINOR }}" + if ([string]::IsNullOrEmpty($minorVersion)) { $minorVersion = "0" } + + $patchVersion = "${{ vars.VERSION_PATCH }}" + if ([string]::IsNullOrEmpty($patchVersion)) { $patchVersion = "0" } + + $previewSuffix = "${{ vars.VERSION_PREVIEW_SUFFIX }}" + if ([string]::IsNullOrEmpty($previewSuffix)) { $previewSuffix = "0" } + + Write-Host "Version variables: MAJOR=$majorVersion, MINOR=$minorVersion, PATCH=$patchVersion, PREVIEW_SUFFIX=$previewSuffix" + + # Determine version based on branch + $ref = "${{ github.ref }}" + if ($ref -eq "refs/heads/main") { + # Main branch: use patch version from repo variables + Write-Host "Main branch: using PATCH_VERSION from repo variables" + + $version = "$majorVersion.$minorVersion.$patchVersion" + $buildNumber = $patchVersion + + # Calculate next patch version for update after successful deployment + $nextPatchVersion = [int]$patchVersion + 1 + echo "NEXT_PATCH_VERSION=$nextPatchVersion" >> $env:GITHUB_OUTPUT + + Write-Host "Main branch version: $version (next patch will be $nextPatchVersion)" + } + elseif ($ref -eq "refs/heads/dev") { + # Dev branch: use preview versioning with incremented suffix + $nextPreviewSuffix = [int]$previewSuffix + 1 + $version = "$majorVersion.$minorVersion.$patchVersion-preview.$nextPreviewSuffix" + $buildNumber = 0 + + # Store the next preview suffix for later update + echo "NEXT_PREVIEW_SUFFIX=$nextPreviewSuffix" >> $env:GITHUB_OUTPUT + Write-Host "Dev branch version: $version (next suffix will be $nextPreviewSuffix)" + } + else { + # Other branches (features/PRs): use CI versioning with timestamp + $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" -AsUTC + $version = "$majorVersion.$minorVersion.$patchVersion-CI-$timestamp" + $buildNumber = 0 + Write-Host "Feature branch version: $version" + } + + # Output variables + echo "VERSION=$version" >> $env:GITHUB_OUTPUT + echo "MAJOR_VERSION=$majorVersion" >> $env:GITHUB_OUTPUT + echo "MINOR_VERSION=$minorVersion" >> $env:GITHUB_OUTPUT + echo "PATCH_VERSION=$patchVersion" >> $env:GITHUB_OUTPUT + echo "BUILD_NUMBER=$buildNumber" >> $env:GITHUB_OUTPUT + echo "BRANCH_TYPE=$(if ($ref -eq 'refs/heads/main') { 'main' } elseif ($ref -eq 'refs/heads/dev') { 'dev' } else { 'feature' })" >> $env:GITHUB_OUTPUT + + Write-Host "Final version: $version" + + - name: Restore dependencies + run: dotnet restore ${{ env.SOLUTION_FILE }} + + - name: Build solution + run: dotnet build ${{ env.SOLUTION_FILE }} --configuration Release --no-restore /p:Version=${{ steps.version.outputs.VERSION }} /p:PackageVersion=${{ steps.version.outputs.VERSION }} + + - name: Test + working-directory: src + run: dotnet test --configuration Release --no-build + + - name: Pack + run: dotnet pack ${{ env.SOLUTION_FILE }} --configuration Release --no-build --output ./artifacts /p:PackageVersion=${{ steps.version.outputs.VERSION }} + + - name: Upload artifacts + uses: actions/upload-artifact@v7 + with: + name: nuget-packages + path: ./artifacts/*.nupkg + retention-days: 7 + + deploy: + needs: build + runs-on: windows-latest + if: | + (github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) || + (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_to_nuget == 'true') + + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Download artifacts + uses: actions/download-artifact@v8 + with: + name: nuget-packages + path: ./artifacts + + - name: Get version data from build + id: version + shell: pwsh + run: | + # Re-calculate version data for this job (since we can't pass complex data between jobs) + $majorVersion = "${{ vars.VERSION_MAJOR }}" + if ([string]::IsNullOrEmpty($majorVersion)) { $majorVersion = "1" } + + $minorVersion = "${{ vars.VERSION_MINOR }}" + if ([string]::IsNullOrEmpty($minorVersion)) { $minorVersion = "0" } + + $patchVersion = "${{ vars.VERSION_PATCH }}" + if ([string]::IsNullOrEmpty($patchVersion)) { $patchVersion = "0" } + + $previewSuffix = "${{ vars.VERSION_PREVIEW_SUFFIX }}" + if ([string]::IsNullOrEmpty($previewSuffix)) { $previewSuffix = "0" } + + $ref = "${{ github.ref }}" + if ($ref -eq "refs/heads/main") { + $nextPatchVersion = [int]$patchVersion + 1 + echo "NEXT_PATCH_VERSION=$nextPatchVersion" >> $env:GITHUB_OUTPUT + echo "BRANCH_TYPE=main" >> $env:GITHUB_OUTPUT + } + elseif ($ref -eq "refs/heads/dev") { + $nextPreviewSuffix = [int]$previewSuffix + 1 + echo "NEXT_PREVIEW_SUFFIX=$nextPreviewSuffix" >> $env:GITHUB_OUTPUT + echo "BRANCH_TYPE=dev" >> $env:GITHUB_OUTPUT + } + else { + echo "BRANCH_TYPE=other" >> $env:GITHUB_OUTPUT + } + + - name: NuGet login - try NUGET_USER + uses: nuget/login@v1 + id: nuget_login_1 + continue-on-error: true + with: + user: ${{ secrets.NUGET_USER }} + + - name: NuGet login - try NUGET_USER_2 + if: steps.nuget_login_1.outcome == 'failure' + uses: nuget/login@v1 + id: nuget_login_2 + with: + user: ${{ secrets.NUGET_USER_2 }} + + - name: Report which account succeeded + shell: pwsh + run: | + if ("${{ steps.nuget_login_1.outcome }}" -eq "success") { + Write-Host "SUCCESS: Authenticated with NUGET_USER (${{ secrets.NUGET_USER }})" + } else { + Write-Host "FAILED: NUGET_USER could not authenticate" + Write-Host "SUCCESS: Authenticated with NUGET_USER_2 (${{ secrets.NUGET_USER_2 }})" + } + + - name: Push to NuGet + id: nuget_push + shell: bash + run: | + if [ "${{ steps.nuget_login_1.outcome }}" == "success" ]; then + API_KEY="${{ steps.nuget_login_1.outputs.NUGET_API_KEY }}" + else + API_KEY="${{ steps.nuget_login_2.outputs.NUGET_API_KEY }}" + fi + dotnet nuget push ./artifacts/*.nupkg --api-key "$API_KEY" --source https://api.nuget.org/v3/index.json --skip-duplicate + + - name: Update preview suffix (dev branch only) + if: steps.version.outputs.BRANCH_TYPE == 'dev' + shell: pwsh + env: + GH_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }} + run: | + $nextSuffix = "${{ steps.version.outputs.NEXT_PREVIEW_SUFFIX }}" + Write-Host "Updating VERSION_PREVIEW_SUFFIX to $nextSuffix" + + try { + gh variable set VERSION_PREVIEW_SUFFIX --body "$nextSuffix" + Write-Host "Successfully updated VERSION_PREVIEW_SUFFIX to $nextSuffix" + } + catch { + Write-Host "WARNING: Failed to update VERSION_PREVIEW_SUFFIX: $($_.Exception.Message)" + # Don't fail the build for this + } + + - name: Update patch version (main branch only) + if: steps.version.outputs.BRANCH_TYPE == 'main' + shell: pwsh + env: + GH_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }} + run: | + $nextPatch = "${{ steps.version.outputs.NEXT_PATCH_VERSION }}" + Write-Host "Updating VERSION_PATCH to $nextPatch and resetting VERSION_PREVIEW_SUFFIX to 0" + + try { + gh variable set VERSION_PATCH --body "$nextPatch" + Write-Host "Successfully updated VERSION_PATCH to $nextPatch" + + gh variable set VERSION_PREVIEW_SUFFIX --body "0" + Write-Host "Successfully reset VERSION_PREVIEW_SUFFIX to 0" + } + catch { + Write-Host "WARNING: Failed to update version variables: $($_.Exception.Message)" + # Don't fail the build for this + } + + create-release: + needs: [build, deploy] + runs-on: windows-latest + permissions: + contents: write + if: | + (github.event_name == 'push' && github.ref == 'refs/heads/main') || + (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' && github.event.inputs.deploy_to_nuget == 'true') + + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Download artifacts + uses: actions/download-artifact@v8 + with: + name: nuget-packages + path: ./artifacts + + - name: Prepare Release Notes + shell: pwsh + run: | + $version = "${{ needs.build.outputs.version }}" + Write-Host "Creating release for version: $version" + + $packages = Get-ChildItem ./artifacts/*.nupkg | ForEach-Object { $_.Name -replace '\.nupkg$', '' } + $packageList = "" + foreach ($package in $packages) { + $packageName = $package -replace "\.$version$", "" + $packageList += "- [$packageName](https://www.nuget.org/packages/$packageName/$version)`n" + } + + $lines = @( + "## NuGet Packages", + $packageList, + "", + "## Installation", + '```', + "dotnet add package Breakdance.Assemblies --version $version", + '```' + ) + $body = $lines -join "`n" + Set-Content -Path "./release-notes.md" -Value $body -Encoding utf8 + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ needs.build.outputs.version }} + name: Release v${{ needs.build.outputs.version }} + body_path: ./release-notes.md + generate_release_notes: true + draft: false + prerelease: false diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml new file mode 100644 index 0000000..55d1121 --- /dev/null +++ b/.github/workflows/pr-validation.yml @@ -0,0 +1,100 @@ +name: PR Validation + +on: + pull_request: + branches: [ main, dev ] + types: [opened, synchronize, reopened] + paths-ignore: + - 'src/CloudNimble.Breakdance.Docs/**' + - 'specs/**' + workflow_dispatch: + +permissions: + contents: read + actions: write + +env: + DOTNET_VERSION: '10.0.x' + SOLUTION_FILE: 'src/CloudNimble.Breakdance.slnx' + +jobs: + validate: + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + fetch-depth: 0 # Full history for versioning + + - name: Install .NET versions + shell: pwsh + run: | + Write-Host "Installing .NET versions..." + $versions = @("8.0", "9.0", "10.0") + foreach ($version in $versions) { + Write-Host "Installing .NET $version..." + Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile "dotnet-install.ps1" + ./dotnet-install.ps1 -Channel $version -InstallDir "$env:ProgramFiles\dotnet" + } + + # Add to PATH for this job + echo "$env:ProgramFiles\dotnet" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + # Verify installation + dotnet --list-sdks + + - name: Get version variables + id: version + shell: pwsh + run: | + # Get version components from repository variables + $majorVersion = "${{ vars.VERSION_MAJOR }}" + if ([string]::IsNullOrEmpty($majorVersion)) { $majorVersion = "1" } + + $minorVersion = "${{ vars.VERSION_MINOR }}" + if ([string]::IsNullOrEmpty($minorVersion)) { $minorVersion = "0" } + + Write-Host "Version variables: MAJOR=$majorVersion, MINOR=$minorVersion" + + # PR validation: always use CI versioning with timestamp (no version increment) + $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" -AsUTC + $version = "$majorVersion.$minorVersion.0-CI-$timestamp" + + Write-Host "PR validation version: $version" + + # Output variables + echo "VERSION=$version" >> $env:GITHUB_OUTPUT + echo "MAJOR_VERSION=$majorVersion" >> $env:GITHUB_OUTPUT + echo "MINOR_VERSION=$minorVersion" >> $env:GITHUB_OUTPUT + + Write-Host "Final version: $version" + + - name: Restore dependencies + run: dotnet restore ${{ env.SOLUTION_FILE }} + + - name: Build solution + run: dotnet build ${{ env.SOLUTION_FILE }} --configuration Release --no-restore /p:Version=${{ steps.version.outputs.VERSION }} /p:PackageVersion=${{ steps.version.outputs.VERSION }} + + - name: Test + working-directory: src + run: dotnet test --configuration Release --no-build + + - name: Pack + run: dotnet pack ${{ env.SOLUTION_FILE }} --configuration Release --no-build --output ./artifacts /p:PackageVersion=${{ steps.version.outputs.VERSION }} + + - name: Upload artifacts + uses: actions/upload-artifact@v7 + with: + name: nuget-packages-pr + path: ./artifacts/*.nupkg + retention-days: 7 + + - name: Validate packages + shell: pwsh + run: | + Write-Host "Validating NuGet packages..." + Get-ChildItem ./artifacts/*.nupkg | ForEach-Object { + Write-Host "Found package: $($_.Name)" + } + Write-Host "PR validation completed successfully" From 401f4b0df37d3b2ad87e1c6b91f2ed8be582caed Mon Sep 17 00:00:00 2001 From: Robert McLaws <1657085+robertmclaws@users.noreply.github.com> Date: Sun, 5 Apr 2026 19:31:06 -0400 Subject: [PATCH 2/5] Update Azurite npm dependencies to fix 12 of 19 vulnerabilities Remaining 7 are transitive dependencies within azurite itself (axios, @azure/identity, tough-cookie, xml2js) awaiting upstream fixes. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../package-lock.json | 187 ++++++++++++------ 1 file changed, 123 insertions(+), 64 deletions(-) diff --git a/src/CloudNimble.Breakdance.Azurite/package-lock.json b/src/CloudNimble.Breakdance.Azurite/package-lock.json index 565e630..f9444d2 100644 --- a/src/CloudNimble.Breakdance.Azurite/package-lock.json +++ b/src/CloudNimble.Breakdance.Azurite/package-lock.json @@ -261,12 +261,12 @@ } }, "node_modules/@azure/identity/node_modules/jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { - "jwa": "^2.0.0", + "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, @@ -1150,33 +1150,62 @@ } }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", + "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/body-parser/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -1623,9 +1652,10 @@ } }, "node_modules/dottie": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz", - "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.7.tgz", + "integrity": "sha512-7lAK2A0b3zZr3UC5aE69CPdCFR4RHW1o2Dr74TqFykxkUCBXSRJum/yPc7g8zRHJqWKomPLHwFLLoUnn8PXXRg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "license": "MIT" }, "node_modules/dunder-proto": { @@ -1876,39 +1906,39 @@ } }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.13.0", + "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -2944,12 +2974,12 @@ } }, "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^1.4.2", "safe-buffer": "^5.0.1" } }, @@ -2969,9 +2999,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash.includes": { @@ -3145,9 +3175,9 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -3444,9 +3474,9 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "license": "MIT" }, "node_modules/pg-connection-string": { @@ -3514,12 +3544,12 @@ } }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -3538,16 +3568,45 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3853,9 +3912,9 @@ "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" }, "node_modules/sequelize": { - "version": "6.37.7", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.37.7.tgz", - "integrity": "sha512-mCnh83zuz7kQxxJirtFD7q6Huy6liPanI67BSlbzSYgVNl5eXVdE2CN1FuAeZwG1SNpGsNRCV+bJAVVnykZAFA==", + "version": "6.37.8", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.37.8.tgz", + "integrity": "sha512-HJ0IQFqcTsTiqbEgiuioYFMSD00TP6Cz7zoTti+zVVBwVe9fEhev9cH6WnM3XU31+ABS356durAb99ZuOthnKw==", "funding": [ { "type": "opencollective", From af44df30eaa9661a6a169b0b4b4ccd9eac0c16b7 Mon Sep 17 00:00:00 2001 From: Robert McLaws <1657085+robertmclaws@users.noreply.github.com> Date: Mon, 6 Apr 2026 01:22:27 -0400 Subject: [PATCH 3/5] Add response snapshot test fixtures and bump DotNetDocs.Sdk to 1.5.4 Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitignore | 1 - src/CloudNimble.Breakdance.Docs/Breakdance.Docs.docsproj | 2 +- .../ResponseFiles/services.odata.org/Entity/filter=query.json | 1 + .../TripPinRESTierService/Airlines/'AA'/root.json | 1 + .../services.odata.org/TripPinRESTierService/Airlines/root.json | 1 + .../Airports/'KSFO'/Location/Address/root.json | 1 + .../TripPinRESTierService/Airports/'KSFO'/Location/root.json | 1 + .../TripPinRESTierService/Airports/'KSFO'/Name/root.json | 1 + .../TripPinRESTierService/Airports/'KSFO'/Name/value.json | 1 + .../filter=containsLocationAddress_'San_Francisco'.json | 1 + .../TripPinRESTierService/Airports/select=Name_IcaoCode.json | 1 + .../GetNearestAirport/lat_=_33_lon_=_-118/root.json | 1 + .../Me/Friends/filter=FriendsanyffFirstName_eq_'Scott'.json | 1 + .../People/'keithpinckney'/expand=Trips/root.json | 1 + .../People/'russellwhyte'/AddressInfo/root.json | 1 + .../People/'russellwhyte'/Gender/value.json | 1 + .../root.json | 1 + .../root.json | 1 + .../expand=Trips/filter=Name_eq_'Trip_in_US'.json | 1 + .../People/'russellwhyte'/expand=Trips/select=TripId_Name.json | 1 + .../People/'russellwhyte'/expand=Trips/top=1.json | 1 + .../TripPinRESTierService/People/'russellwhyte'/root.json | 1 + .../People/'scottketchum'/Trips/orderby=EndsAt_desc.json | 1 + .../services.odata.org/TripPinRESTierService/People/count.json | 1 + .../People/filter=FirstName_eq_'Scott'.json | 1 + ...vice.Sample.TrippinInMemory.Models.PersonGender'Female'.json | 1 + .../services.odata.org/TripPinRESTierService/People/root.json | 1 + .../TripPinRESTierService/People/skip=18.json | 1 + .../services.odata.org/TripPinRESTierService/People/top=2.json | 1 + .../TripPinRESTierService/ResetDataSource/root.json | 1 + .../ResponseFiles/services.odata.org/metadata.xml | 1 + .../ResponseFiles/services.odata.org/root.json | 1 + .../orderby=TestCaseTestOfferingCompanyCompanyNameT.json | 1 + 33 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/Entity/filter=query.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airlines/'AA'/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airlines/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Location/Address/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Location/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Name/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Name/value.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/filter=containsLocationAddress_'San_Francisco'.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/select=Name_IcaoCode.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/GetNearestAirport/lat_=_33_lon_=_-118/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Me/Friends/filter=FriendsanyffFirstName_eq_'Scott'.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'keithpinckney'/expand=Trips/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/AddressInfo/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/Gender/value.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/Microsoft.OData.Service.Sample.TrippinInMemory.Models.ShareTrip/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/Trips/0/Microsoft.OData.Service.Sample.TrippinInMemory.Models.GetInvolvedPeople/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/expand=Trips/filter=Name_eq_'Trip_in_US'.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/expand=Trips/select=TripId_Name.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/expand=Trips/top=1.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'scottketchum'/Trips/orderby=EndsAt_desc.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/count.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/filter=FirstName_eq_'Scott'.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/filter=Gender_eq_Microsoft.OData.Service.Sample.TrippinInMemory.Models.PersonGender'Female'.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/skip=18.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/top=2.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/ResetDataSource/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/metadata.xml create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/root.json create mode 100644 src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/test.somewebsite.io/v2/TestCaseStages/expand=TestCase/expand=Test/expand=Offering/expand=CompanyTemplateDepartmentCaseStageType/orderby=TestCaseTestOfferingCompanyCompanyNameT.json diff --git a/.gitignore b/.gitignore index e7de818..f93daf8 100644 --- a/.gitignore +++ b/.gitignore @@ -301,7 +301,6 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk -/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/ /.claude/settings.local.json /.playwright-mcp /src/.claude/settings.local.json diff --git a/src/CloudNimble.Breakdance.Docs/Breakdance.Docs.docsproj b/src/CloudNimble.Breakdance.Docs/Breakdance.Docs.docsproj index 907ab13..ca96460 100644 --- a/src/CloudNimble.Breakdance.Docs/Breakdance.Docs.docsproj +++ b/src/CloudNimble.Breakdance.Docs/Breakdance.Docs.docsproj @@ -1,4 +1,4 @@ - + Mintlify diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/Entity/filter=query.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/Entity/filter=query.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/Entity/filter=query.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airlines/'AA'/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airlines/'AA'/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airlines/'AA'/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airlines/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airlines/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airlines/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Location/Address/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Location/Address/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Location/Address/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Location/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Location/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Location/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Name/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Name/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Name/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Name/value.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Name/value.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/'KSFO'/Name/value.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/filter=containsLocationAddress_'San_Francisco'.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/filter=containsLocationAddress_'San_Francisco'.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/filter=containsLocationAddress_'San_Francisco'.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/select=Name_IcaoCode.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/select=Name_IcaoCode.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Airports/select=Name_IcaoCode.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/GetNearestAirport/lat_=_33_lon_=_-118/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/GetNearestAirport/lat_=_33_lon_=_-118/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/GetNearestAirport/lat_=_33_lon_=_-118/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Me/Friends/filter=FriendsanyffFirstName_eq_'Scott'.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Me/Friends/filter=FriendsanyffFirstName_eq_'Scott'.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/Me/Friends/filter=FriendsanyffFirstName_eq_'Scott'.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'keithpinckney'/expand=Trips/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'keithpinckney'/expand=Trips/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'keithpinckney'/expand=Trips/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/AddressInfo/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/AddressInfo/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/AddressInfo/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/Gender/value.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/Gender/value.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/Gender/value.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/Microsoft.OData.Service.Sample.TrippinInMemory.Models.ShareTrip/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/Microsoft.OData.Service.Sample.TrippinInMemory.Models.ShareTrip/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/Microsoft.OData.Service.Sample.TrippinInMemory.Models.ShareTrip/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/Trips/0/Microsoft.OData.Service.Sample.TrippinInMemory.Models.GetInvolvedPeople/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/Trips/0/Microsoft.OData.Service.Sample.TrippinInMemory.Models.GetInvolvedPeople/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/Trips/0/Microsoft.OData.Service.Sample.TrippinInMemory.Models.GetInvolvedPeople/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/expand=Trips/filter=Name_eq_'Trip_in_US'.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/expand=Trips/filter=Name_eq_'Trip_in_US'.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/expand=Trips/filter=Name_eq_'Trip_in_US'.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/expand=Trips/select=TripId_Name.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/expand=Trips/select=TripId_Name.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/expand=Trips/select=TripId_Name.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/expand=Trips/top=1.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/expand=Trips/top=1.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/expand=Trips/top=1.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'russellwhyte'/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'scottketchum'/Trips/orderby=EndsAt_desc.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'scottketchum'/Trips/orderby=EndsAt_desc.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/'scottketchum'/Trips/orderby=EndsAt_desc.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/count.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/count.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/count.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/filter=FirstName_eq_'Scott'.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/filter=FirstName_eq_'Scott'.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/filter=FirstName_eq_'Scott'.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/filter=Gender_eq_Microsoft.OData.Service.Sample.TrippinInMemory.Models.PersonGender'Female'.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/filter=Gender_eq_Microsoft.OData.Service.Sample.TrippinInMemory.Models.PersonGender'Female'.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/filter=Gender_eq_Microsoft.OData.Service.Sample.TrippinInMemory.Models.PersonGender'Female'.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/skip=18.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/skip=18.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/skip=18.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/top=2.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/top=2.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/People/top=2.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/ResetDataSource/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/ResetDataSource/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/TripPinRESTierService/ResetDataSource/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/metadata.xml b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/metadata.xml new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/metadata.xml @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/root.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/root.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/services.odata.org/root.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/test.somewebsite.io/v2/TestCaseStages/expand=TestCase/expand=Test/expand=Offering/expand=CompanyTemplateDepartmentCaseStageType/orderby=TestCaseTestOfferingCompanyCompanyNameT.json b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/test.somewebsite.io/v2/TestCaseStages/expand=TestCase/expand=Test/expand=Offering/expand=CompanyTemplateDepartmentCaseStageType/orderby=TestCaseTestOfferingCompanyCompanyNameT.json new file mode 100644 index 0000000..87b8ff2 --- /dev/null +++ b/src/CloudNimble.Breakdance.Tests.Assemblies/ResponseFiles/test.somewebsite.io/v2/TestCaseStages/expand=TestCase/expand=Test/expand=Offering/expand=CompanyTemplateDepartmentCaseStageType/orderby=TestCaseTestOfferingCompanyCompanyNameT.json @@ -0,0 +1 @@ +{ } \ No newline at end of file From 97aef02cc35cf9c07c18b31beb3f85397d716e90 Mon Sep 17 00:00:00 2001 From: Robert McLaws <1657085+robertmclaws@users.noreply.github.com> Date: Mon, 6 Apr 2026 01:25:17 -0400 Subject: [PATCH 4/5] Build fixes Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build-and-deploy.yml | 31 ++++---------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index f6d11d8..9b5d67f 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -141,6 +141,7 @@ jobs: deploy: needs: build runs-on: windows-latest + environment: production if: | (github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_to_nuget == 'true') @@ -187,40 +188,16 @@ jobs: echo "BRANCH_TYPE=other" >> $env:GITHUB_OUTPUT } - - name: NuGet login - try NUGET_USER + - name: NuGet login (Trusted Publishing) uses: nuget/login@v1 - id: nuget_login_1 - continue-on-error: true + id: nuget_login with: user: ${{ secrets.NUGET_USER }} - - name: NuGet login - try NUGET_USER_2 - if: steps.nuget_login_1.outcome == 'failure' - uses: nuget/login@v1 - id: nuget_login_2 - with: - user: ${{ secrets.NUGET_USER_2 }} - - - name: Report which account succeeded - shell: pwsh - run: | - if ("${{ steps.nuget_login_1.outcome }}" -eq "success") { - Write-Host "SUCCESS: Authenticated with NUGET_USER (${{ secrets.NUGET_USER }})" - } else { - Write-Host "FAILED: NUGET_USER could not authenticate" - Write-Host "SUCCESS: Authenticated with NUGET_USER_2 (${{ secrets.NUGET_USER_2 }})" - } - - name: Push to NuGet id: nuget_push shell: bash - run: | - if [ "${{ steps.nuget_login_1.outcome }}" == "success" ]; then - API_KEY="${{ steps.nuget_login_1.outputs.NUGET_API_KEY }}" - else - API_KEY="${{ steps.nuget_login_2.outputs.NUGET_API_KEY }}" - fi - dotnet nuget push ./artifacts/*.nupkg --api-key "$API_KEY" --source https://api.nuget.org/v3/index.json --skip-duplicate + run: dotnet nuget push ./artifacts/*.nupkg --api-key ${{ steps.nuget_login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate - name: Update preview suffix (dev branch only) if: steps.version.outputs.BRANCH_TYPE == 'dev' From d86d290d054da48c64548946b90a1b62a61b4494 Mon Sep 17 00:00:00 2001 From: Robert McLaws <1657085+robertmclaws@users.noreply.github.com> Date: Mon, 6 Apr 2026 01:29:16 -0400 Subject: [PATCH 5/5] Enable git long paths for Windows CI runners Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build-and-deploy.yml | 3 +++ .github/workflows/pr-validation.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 9b5d67f..010be64 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -34,6 +34,9 @@ jobs: version: ${{ steps.version.outputs.VERSION }} steps: + - name: Enable long paths + run: git config --system core.longpaths true + - name: Checkout code uses: actions/checkout@v6 with: diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml index 55d1121..cb7bef2 100644 --- a/.github/workflows/pr-validation.yml +++ b/.github/workflows/pr-validation.yml @@ -22,6 +22,9 @@ jobs: runs-on: windows-latest steps: + - name: Enable long paths + run: git config --system core.longpaths true + - name: Checkout code uses: actions/checkout@v6 with: