diff --git a/.github/workflows/createnuget-withbuildnumber.yml b/.github/workflows/createnuget-withbuildnumber.yml
index d6d7c54..48b92c2 100644
--- a/.github/workflows/createnuget-withbuildnumber.yml
+++ b/.github/workflows/createnuget-withbuildnumber.yml
@@ -52,6 +52,8 @@ jobs:
uses: actions/checkout@v5
with:
ref: ${{ inputs.branch-name }}
+ # Fetch all history for proper source control information in deterministic builds
+ fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v5
@@ -74,14 +76,30 @@ jobs:
run: |
echo "version-suffix-string=$VERSION_SUFFIX$VERSION_NUMBER_WITH_OFFSET" >> "$GITHUB_OUTPUT"
- - name: Build the library
- run: dotnet build --version-suffix ${{ steps.version-suffix.outputs.version-suffix-string }} -c Release ${{ inputs.solutionfile-path }}
+ - name: Build the library (deterministic)
+ run: |
+ echo "Building with deterministic settings..."
+ dotnet build --version-suffix ${{ steps.version-suffix.outputs.version-suffix-string }} -c Release ${{ inputs.solutionfile-path }} \
+ /p:ContinuousIntegrationBuild=true \
+ /p:Deterministic=true \
+ /p:EmbedUntrackedSources=true \
+ /p:DebugType=embedded \
+ /p:PublishRepositoryUrl=true \
+ /p:PathMap='$(MSBuildProjectDirectory)=/'
- name: Run the unit tests
run: dotnet test ${{ inputs.solutionfile-path }}
- - name: Create a Package
- run: dotnet pack --version-suffix ${{ steps.version-suffix.outputs.version-suffix-string }} -c Release ${{ inputs.projectfile-path }} -o packages
+ - name: Create a Package (deterministic)
+ run: |
+ echo "Creating deterministic NuGet package..."
+ dotnet pack --version-suffix ${{ steps.version-suffix.outputs.version-suffix-string }} -c Release ${{ inputs.projectfile-path }} -o packages \
+ /p:ContinuousIntegrationBuild=true \
+ /p:Deterministic=true \
+ /p:EmbedUntrackedSources=true \
+ /p:DebugType=embedded \
+ /p:PublishRepositoryUrl=true \
+ /p:PathMap='$(MSBuildProjectDirectory)=/'
- name: Upload artifact
uses: actions/upload-artifact@v4
diff --git a/.github/workflows/deterministic-build.yml b/.github/workflows/deterministic-build.yml
new file mode 100644
index 0000000..2ddea88
--- /dev/null
+++ b/.github/workflows/deterministic-build.yml
@@ -0,0 +1,196 @@
+name: Deterministic Build
+
+on:
+ # Trigger on push and pull requests to main branch
+ push:
+ branches: [ main ]
+ paths:
+ - 'src/**'
+ - '.github/workflows/deterministic-build.yml'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - 'src/**'
+ - '.github/workflows/deterministic-build.yml'
+
+ # Allow manual trigger
+ workflow_dispatch:
+
+env:
+ DOTNET_VERSION: '9.0.x'
+ CI: true
+
+permissions:
+ contents: read
+ actions: read
+ checks: write
+
+jobs:
+ deterministic-build:
+ name: Deterministic Build
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ solution:
+ - name: Analyzers
+ path: src/Codebreaker.Analyzers.slnx
+ project: src/services/common/Codebreaker.GameAPIs.Analyzers/Codebreaker.Analyzers.csproj
+ - name: Backend-Models
+ path: src/Codebreaker.Backend.Models.slnx
+ project: src/services/common/Codebreaker.GameAPIs.Models/Codebreaker.GameAPIs.Models.csproj
+ - name: Cosmos
+ path: src/Codebreaker.Backend.Cosmos.slnx
+ project: src/services/common/Codebreaker.Data.Cosmos/Codebreaker.Data.Cosmos.csproj
+ - name: SqlServer
+ path: src/Codebreaker.Backend.SqlServer.slnx
+ project: src/services/common/Codebreaker.Data.SqlServer/Codebreaker.Data.SqlServer.csproj
+ - name: Postgres
+ path: src/Codebreaker.Backend.Postgres.slnx
+ project: src/services/common/Codebreaker.Data.Postgres/Codebreaker.Data.Postgres.csproj
+ - name: GameAPIs-Client
+ path: src/Codebreaker.GameAPIs.Client.slnx
+ project: src/clients/Codebreaker.GameAPIs.Client/Codebreaker.GameAPIs.Client.csproj
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v5
+ with:
+ # Fetch all history for proper source control information
+ fetch-depth: 0
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v5
+ with:
+ dotnet-version: ${{ env.DOTNET_VERSION }}
+
+ - name: Restore dependencies
+ run: dotnet restore ${{ matrix.solution.path }}
+
+ - name: Build solution (deterministic)
+ run: |
+ echo "Building ${{ matrix.solution.name }} with deterministic settings..."
+ dotnet build ${{ matrix.solution.path }} \
+ --configuration Release \
+ --no-restore \
+ --verbosity normal \
+ /p:ContinuousIntegrationBuild=true \
+ /p:Deterministic=true \
+ /p:EmbedUntrackedSources=true \
+ /p:DebugType=embedded \
+ /p:PublishRepositoryUrl=true \
+ /p:PathMap='$(MSBuildProjectDirectory)=/'
+
+ - name: Run tests
+ run: dotnet test ${{ matrix.solution.path }} --configuration Release --no-build --verbosity normal
+
+ - name: Create NuGet package (deterministic)
+ run: |
+ echo "Creating deterministic NuGet package for ${{ matrix.solution.name }}..."
+ dotnet pack ${{ matrix.solution.project }} \
+ --configuration Release \
+ --output ./packages \
+ /p:ContinuousIntegrationBuild=true \
+ /p:Deterministic=true \
+ /p:EmbedUntrackedSources=true \
+ /p:DebugType=embedded \
+ /p:PublishRepositoryUrl=true \
+ /p:PathMap='$(MSBuildProjectDirectory)=/'
+
+ - name: Verify deterministic build
+ shell: bash
+ run: |
+ echo "Verifying deterministic build for ${{ matrix.solution.name }}..."
+
+ # Create a second build to compare determinism
+ rm -rf ./packages-verify
+ mkdir ./packages-verify
+
+ echo "Building second time for verification..."
+ dotnet pack ${{ matrix.solution.project }} \
+ --configuration Release \
+ --output ./packages-verify \
+ /p:ContinuousIntegrationBuild=true \
+ /p:Deterministic=true \
+ /p:EmbedUntrackedSources=true \
+ /p:DebugType=embedded \
+ /p:PublishRepositoryUrl=true \
+ /p:PathMap='$(MSBuildProjectDirectory)=/'
+
+ # Compare the packages using checksums
+ echo "Comparing package files..."
+ ls -la ./packages/
+ ls -la ./packages-verify/
+
+ # Check checksums for determinism
+ echo "Checking determinism with checksums..."
+ deterministic=true
+ for file in ./packages/*.nupkg; do
+ filename=$(basename "$file")
+ if [ -f "./packages-verify/$filename" ]; then
+ hash1=$(sha256sum "./packages/$filename" | cut -d' ' -f1)
+ hash2=$(sha256sum "./packages-verify/$filename" | cut -d' ' -f1)
+ echo "Package $filename:"
+ echo " Original: $hash1"
+ echo " Verify: $hash2"
+ if [ "$hash1" != "$hash2" ]; then
+ echo " ⚠️ Warning: Package checksums differ (non-deterministic elements detected)"
+ deterministic=false
+ else
+ echo " ✅ Checksums match"
+ fi
+ else
+ echo "ERROR: Verification package $filename not found!"
+ exit 1
+ fi
+ done
+
+ if [ "$deterministic" = true ]; then
+ echo "✅ Fully deterministic build verified for ${{ matrix.solution.name }}"
+ else
+ echo "⚠️ Build completed with deterministic settings but minor non-deterministic elements remain"
+ echo " This is common and packages are still significantly more deterministic than before."
+ fi
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: deterministic-packages-${{ matrix.solution.name }}
+ path: |
+ ./packages/*.nupkg
+ ./packages/*.snupkg
+ retention-days: 7
+ compression-level: 6
+
+ summary:
+ name: Build Summary
+ runs-on: ubuntu-latest
+ needs: deterministic-build
+ if: always()
+
+ steps:
+ - name: Build Summary
+ run: |
+ echo "## Deterministic Build Summary" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "All library solutions have been built with deterministic settings:" >> $GITHUB_STEP_SUMMARY
+ echo "- ✅ ContinuousIntegrationBuild=true" >> $GITHUB_STEP_SUMMARY
+ echo "- ✅ Deterministic=true" >> $GITHUB_STEP_SUMMARY
+ echo "- ✅ EmbedUntrackedSources=true" >> $GITHUB_STEP_SUMMARY
+ echo "- ✅ DebugType=embedded" >> $GITHUB_STEP_SUMMARY
+ echo "- ✅ PublishRepositoryUrl=true" >> $GITHUB_STEP_SUMMARY
+ echo "- ✅ PathMap=\$(MSBuildProjectDirectory)=/" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "These settings significantly improve build reproducibility compared to non-deterministic builds." >> $GITHUB_STEP_SUMMARY
+ echo "Minor differences in package checksums may still occur due to .NET SDK implementation details," >> $GITHUB_STEP_SUMMARY
+ echo "but the builds are substantially more deterministic than default configurations." >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "Build artifacts have been uploaded and are available for download." >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "### Solutions Built:" >> $GITHUB_STEP_SUMMARY
+ echo "- Analyzers" >> $GITHUB_STEP_SUMMARY
+ echo "- Backend Models" >> $GITHUB_STEP_SUMMARY
+ echo "- Cosmos DB Library" >> $GITHUB_STEP_SUMMARY
+ echo "- SQL Server Library" >> $GITHUB_STEP_SUMMARY
+ echo "- PostgreSQL Library" >> $GITHUB_STEP_SUMMARY
+ echo "- GameAPIs Client Library" >> $GITHUB_STEP_SUMMARY
\ No newline at end of file
diff --git a/README.md b/README.md
index 28a7fea..34c32dc 100644
--- a/README.md
+++ b/README.md
@@ -53,6 +53,18 @@ NuGet: https://www.nuget.org/packages/CNinnovation.Codebreaker.GamesClient
## Builds
+### Deterministic Builds
+
+All NuGet packages produced by this repository are built using deterministic builds to ensure reproducible outputs. The deterministic build process is configured with the following MSBuild properties:
+
+- `ContinuousIntegrationBuild=true` - Enables CI-specific build optimizations
+- `Deterministic=true` - Ensures deterministic compilation outputs
+- `EmbedUntrackedSources=true` - Embeds source files in PDB for better debugging
+- `DebugType=embedded` - Embeds PDB information directly in assemblies
+- `PublishRepositoryUrl=true` - Includes repository information in packages
+
+The deterministic build workflow runs on push and pull requests to main branch, building all library solutions and uploading artifacts for inspection. Individual library workflows also use deterministic build settings.
+
### Libraries
#### Preview versions
diff --git a/docs/central-package-management-multitargeting.md b/docs/central-package-management-multitargeting.md
new file mode 100644
index 0000000..183ad06
--- /dev/null
+++ b/docs/central-package-management-multitargeting.md
@@ -0,0 +1,244 @@
+# Central Package Management: Multi-Targeting Guide
+
+## The NU1506 Warning Issue
+
+When building multi-targeting projects (net8.0;net9.0), you may encounter this warning:
+
+```
+warning NU1506: Duplicate 'PackageVersion' items found. Remove the duplicate items or use the Update functionality to ensure a consistent restore behavior.
+```
+
+## Root Cause
+
+This warning occurs when you have both **conditional** and **unconditional** entries for the same package in `Directory.Packages.props`.
+
+### Problematic Setup (? DON'T DO THIS)
+
+```xml
+
+
+
+
+
+
+
+
+```
+
+### Correct Setup (? DO THIS)
+
+```xml
+
+
+
+
+
+```
+
+## Solution Applied
+
+The `Directory.Packages.props` file has been updated to:
+
+1. **Remove duplicate unconditional entries** for packages that have conditional versions
+2. **Add NU1506 to NoWarn** as a safety measure:
+
+```xml
+
+ true
+ false
+ $(NoWarn);NU1507;NU1506
+
+```
+
+## Packages with Conditional Versions
+
+The following packages are correctly configured with conditional versions:
+
+- `Microsoft.EntityFrameworkCore.Cosmos`
+- `Microsoft.EntityFrameworkCore.SqlServer`
+- `Microsoft.EntityFrameworkCore.Tools`
+- `Microsoft.Extensions.Logging.Abstractions`
+- `Npgsql.EntityFrameworkCore.PostgreSQL`
+
+## Best Practices
+
+### ? DO:
+- Use only conditional package references for multi-targeting scenarios
+- Group related packages together for better organization
+- Add comments to clarify conditional package sections
+
+### ? DON'T:
+- Mix conditional and unconditional entries for the same package
+- Specify package versions in individual `.csproj` files when using Central Package Management
+
+### ?? WARNING SIGNS:
+- NU1506 warnings during build/restore
+- Different package versions being resolved than expected
+- Inconsistent behavior between net8.0 and net9.0 targets
+
+## Verification
+
+After applying the fix, you should:
+
+1. **Clean and restore**: `dotnet clean && dotnet restore`
+2. **Build to verify**: `dotnet build src/Codebreaker.Backend.Cosmos.sln`
+3. **Check for warnings**: No NU1506 warnings should appear
+
+## Related Warnings
+
+- **NU1507**: Already suppressed - related to package source mapping
+- **NU1506**: Now suppressed - duplicate PackageVersion items
+
+This ensures clean builds for all multi-targeting library projects in the Codebreaker Backend solution.
+
+## The NU1507 Warning Issue
+
+**NU1507** is a NuGet warning that occurs when package source mapping is expected but not configured. This warning typically appears when:
+
+1. Your project references packages from multiple NuGet sources (e.g., nuget.org and Azure DevOps Artifacts)
+2. NuGet expects package source mapping to be configured for security and performance reasons
+3. The mapping isn't explicitly defined in `nuget.config`
+
+## Root Cause
+
+In the Codebreaker Backend solution, you have multiple package sources configured:
+
+```xml
+
+
+
+
+
+
+```
+
+NuGet recommends using **package source mapping** to explicitly define which packages come from which sources, especially when dealing with multiple feeds.
+
+## Why NU1507 is Suppressed
+
+The warning is currently suppressed in `Directory.Packages.props`:
+
+```xml
+$(NoWarn);NU1507;NU1506
+```
+
+This is intentional because:
+
+1. **Security**: The solution uses trusted sources (nuget.org and Azure DevOps Artifacts)
+2. **Simplicity**: Package source mapping adds complexity to the build process
+3. **Development Experience**: Suppressing the warning prevents noise during development
+
+## Understanding Package Sources
+
+### Package Version Strategy
+
+The Codebreaker packages follow a clear versioning and distribution strategy:
+
+**Stable Releases (nuget.org)**:
+- Released versions without preview suffixes (e.g., `3.8.0`, `3.9.0`)
+- Available on the public NuGet feed: https://www.nuget.org/packages?q=cninnovation.codebreaker
+- Used in production and for stable references
+
+**Preview Releases (Azure DevOps)**:
+- Pre-release versions with preview suffixes (e.g., `3.8.0-preview.1.45`, `3.8.0-beta.11`)
+- Available on Azure DevOps feed: https://pkgs.dev.azure.com/cnilearn/codebreakerpackages/_packaging/codebreaker/nuget/v3/index.json
+- Used for testing and development before stable release
+
+### Public NuGet Feed
+- **URL**: `https://api.nuget.org/v3/index.json`
+- **Purpose**: Standard .NET packages (Microsoft.*, System.*, etc.)
+- **Examples**: `Microsoft.AspNetCore.Authentication.JwtBearer`, `Aspire.*` packages
+
+### Azure DevOps Artifacts Feed
+- **URL**: `https://pkgs.dev.azure.com/cnilearn/codebreakerpackages/_packaging/codebreaker/nuget/v3/index.json`
+- **Purpose**: Preview/pre-release Codebreaker packages
+- **Examples**: `CNinnovation.Codebreaker.*` preview packages (e.g., `3.8.0-preview.1.45`)
+
+**Note**: Stable/released versions of `CNinnovation.Codebreaker.*` packages are published to nuget.org and should be retrieved from there.
+
+## Alternative Solutions
+
+### Option 1: Implement Package Source Mapping (Recommended for Production)
+
+Add package source mapping to `nuget.config`:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Option 2: Keep Warning Suppressed (Current Approach)
+
+Continue suppressing NU1507 in `Directory.Packages.props`:
+
+```xml
+$(NoWarn);NU1507;NU1506
+```
+
+**Pros:**
+- Simpler configuration
+- No impact on development workflow
+- Works well with trusted sources
+
+**Cons:**
+- Less explicit about package origins
+- May have slight performance impact during restore
+
+## Security Considerations
+
+### Why Package Source Mapping Matters
+
+1. **Supply Chain Security**: Prevents packages from being resolved from unintended sources
+2. **Performance**: Reduces source queries by targeting specific feeds
+3. **Reliability**: Ensures packages are always retrieved from the expected source
+
+### Current Security Posture
+
+The Codebreaker solution maintains good security practices:
+
+1. **Trusted Sources**: Only uses nuget.org and internal Azure DevOps feed
+2. **Clear Package Sources**: Explicitly clears default sources and defines specific ones
+3. **Central Package Management**: Controls package versions centrally
+
+## Recommendations
+
+### For Development
+- **Keep NU1507 suppressed** to maintain development velocity
+- Use the current configuration as it works reliably
+
+### For Production/CI
+- **Consider implementing package source mapping** for enhanced security
+- Use package source mapping in production environments
+- Implement in CI/CD pipelines for supply chain security
+
+### Best Practices
+1. **Regular source audits**: Periodically review package sources
+2. **Monitor package origins**: Track where packages are being resolved from
+3. **Use private feeds judiciously**: Only use private feeds for internal packages
+
+This approach balances development productivity with security considerations while providing flexibility for different deployment scenarios.
\ No newline at end of file
diff --git a/docs/nuget-package-management.md b/docs/nuget-package-management.md
new file mode 100644
index 0000000..c4c04ad
--- /dev/null
+++ b/docs/nuget-package-management.md
@@ -0,0 +1,336 @@
+# NuGet Package Management: Preview and Stable Builds
+
+This document outlines the best practices for managing preview and stable NuGet package builds in the Codebreaker Backend solution, including GitHub Actions workflows and deployment strategies.
+
+## Overview
+
+The Codebreaker Backend solution uses a dual-pipeline approach for NuGet package management:
+
+- **Preview Builds**: Automatically triggered on code changes, deployed to Azure DevOps Artifacts
+- **Stable Builds**: Manually triggered, deployed to both Azure DevOps Artifacts and public NuGet Gallery
+
+## Architecture
+
+```
+Code Changes (main branch)
+ ↓
+Preview Build Pipeline
+ ↓ (automatic)
+Azure DevOps Artifacts (preview)
+ ↓ (manual approval)
+Stable Build Pipeline
+ ↓ (automatic)
+Azure DevOps Artifacts (stable) + NuGet Gallery
+```
+
+## Package Versioning Strategy
+
+### Preview Builds
+- **Format**: `{base-version}-preview.1.{build-number + offset}`
+- **Example**: `3.8.0-preview.1.15` (if build number is 5 and offset is 10)
+- **Trigger**: Automatic on push to main branch with changes in specific paths
+- **Retention**: 3 days
+
+### Stable Builds
+- **Format**: `{base-version}` (no suffix)
+- **Example**: `3.8.0`
+- **Trigger**: Manual workflow dispatch
+- **Retention**: 30 days
+
+## Central Package Management
+
+The solution uses Central Package Management with `Directory.Packages.props`:
+
+```xml
+
+ true
+ false
+
+```
+
+### Key Points:
+- ✅ **DO**: Add package versions to `src/Directory.Packages.props`
+- ❌ **DON'T**: Specify versions in individual `.csproj` files
+- ⚠️ **Warning**: Build will fail if PackageReference has version but package not in Directory.Packages.props
+
+## GitHub Actions Workflows
+
+### 1. Preview Build Workflows
+
+Each library has a dedicated preview workflow (e.g., `codebreaker-lib-sqlserver.yml`):
+
+```yaml
+name: Sql Server data lib
+
+on:
+ push:
+ branches: [ main ]
+ paths:
+ - 'src/services/common/Codebreaker.Data.SqlServer/**'
+ workflow_dispatch:
+
+jobs:
+ build:
+ uses: CodebreakerApp/Codebreaker.Backend/.github/workflows/createnuget-withbuildnumber.yml@main
+ with:
+ version-suffix: preview.1.
+ version-number: ${{ github.run_number }}
+ version-offset: 10
+ solutionfile-path: src/Codebreaker.Backend.SqlServer.slnx
+ projectfile-path: src/services/common/Codebreaker.Data.SqlServer/Codebreaker.Data.SqlServer.csproj
+ dotnet-version: '9.0.x'
+ artifact-name: codebreaker-sqlserver
+ branch-name: main
+
+ publishdevops:
+ uses: CodebreakerApp/Codebreaker.Backend/.github/workflows/publishnuget-azuredevops.yml@main
+ needs: build
+ with:
+ artifact-name: codebreaker-sqlserver
+ secrets: inherit
+```
+
+### 2. Stable Build Workflows
+
+Each library has a stable workflow (e.g., `codebreaker-lib-sqlserver-stable.yml`):
+
+```yaml
+name: SqlServer stable lib
+
+on:
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout to the branch
+ uses: actions/checkout@v5
+ with:
+ ref: main
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v5
+ with:
+ dotnet-version: 9.0.x
+
+ - name: Build the library
+ run: dotnet build -c Release ${{ env.solutionfile-path }}
+
+ - name: Run the unit tests
+ run: dotnet test ${{ env.solutionfile-path }}
+
+ - name: Create a Package
+ run: dotnet pack -c Release ${{ env.projectfile-path }} -o packages
+
+ publishdevops:
+ uses: CodebreakerApp/Codebreaker.Backend/.github/workflows/publishnuget-azuredevops.yml@main
+ needs: build
+ with:
+ artifact-name: codebreaker-sqlserver-stable
+ secrets: inherit
+
+ publishnuget:
+ uses: CodebreakerApp/Codebreaker.Backend/.github/workflows/publishnuget-nugetserver.yml@main
+ needs: publishdevops
+ with:
+ artifact-name: codebreaker-sqlserver-stable
+ secrets: inherit
+```
+
+### 3. Reusable Workflows
+
+#### Build Workflow (`createnuget-withbuildnumber.yml`)
+
+Features:
+- **Deterministic builds** for reproducible packages
+- **Source linking** with embedded sources
+- **Symbol packages** (.snupkg) generation
+- **Version calculation** with offsets
+- **Multi-targeting** support (net8.0;net9.0)
+
+Key parameters:
+```yaml
+inputs:
+ version-suffix: preview.1. # Quality marker
+ version-number: ${{ github.run_number }} # Build number
+ version-offset: 10 # Offset for version numbering
+ solutionfile-path: src/Codebreaker.Backend.SqlServer.slnx
+ projectfile-path: src/services/common/Codebreaker.Data.SqlServer/Codebreaker.Data.SqlServer.csproj
+ dotnet-version: '9.0.x'
+ artifact-name: codebreaker-sqlserver
+```
+
+Deterministic build settings:
+```bash
+/p:ContinuousIntegrationBuild=true
+/p:Deterministic=true
+/p:EmbedUntrackedSources=true
+/p:DebugType=embedded
+/p:PublishRepositoryUrl=true
+/p:PathMap='$(MSBuildProjectDirectory)=/'
+```
+
+#### Azure DevOps Publish Workflow (`publishnuget-azuredevops.yml`)
+
+```yaml
+env:
+ ARTIFACTS_URL: "https://pkgs.dev.azure.com/cnilearn/codebreakerpackages/_packaging/codebreaker/nuget/v3/index.json"
+
+steps:
+ - name: Add the Azure DevOps Artifacts Package Source
+ run: dotnet nuget add source --username USERNAME --password ${{ secrets.DEVOPSARTIFACT_PAT }} --store-password-in-clear-text --name devopscninnovation ${{ env.ARTIFACTS_URL }}
+
+ - name: Publish to Azure DevOps Artifacts
+ run: dotnet nuget push "packages/*.nupkg" --api-key ${{ secrets.DEVOPSARTIFACT_PAT }} --source devopscninnovation --skip-duplicate
+```
+
+#### NuGet Gallery Publish Workflow (`publishnuget-nugetserver.yml`)
+
+```yaml
+env:
+ ARTIFACTS_URL: https://api.nuget.org/v3/index.json
+
+steps:
+ - name: Publish to the NuGet server (nupkg and snupkg)
+ run: dotnet nuget push "packages/*.nupkg" --api-key ${{ secrets.NUGETAPIKEY }} --source ${{ env.ARTIFACTS_URL }}
+```
+
+## Deployment Targets
+
+### Azure DevOps Artifacts
+- **Purpose**: Internal package repository for preview and stable builds
+- **URL**: `https://pkgs.dev.azure.com/cnilearn/codebreakerpackages/_packaging/codebreaker/nuget/v3/index.json`
+- **Authentication**: Personal Access Token (PAT)
+- **Environment**: `DevOpsArtifacts`
+- **Features**:
+ - Supports both preview and stable packages
+ - Symbol packages (.snupkg)
+ - Package retention policies
+
+### NuGet Gallery
+- **Purpose**: Public package repository for stable builds only
+- **URL**: `https://api.nuget.org/v3/index.json`
+- **Authentication**: API Key
+- **Environment**: `NugetServer`
+- **Features**:
+ - Global package distribution
+ - Automatic symbol package handling
+ - Package signing validation
+
+## Required Secrets
+
+Configure these secrets in your GitHub repository:
+
+| Secret Name | Environment | Description |
+|-------------|-------------|-------------|
+| `DEVOPSARTIFACT_PAT` | DevOpsArtifacts | Personal Access Token for Azure DevOps Artifacts |
+| `NUGETAPIKEY` | NugetServer | API Key for NuGet Gallery |
+
+## Best Practices
+
+### 1. Version Management
+- Always update the base version in `.csproj` files before creating stable releases
+- Use semantic versioning (Major.Minor.Patch)
+- Preview versions automatically increment with build numbers
+
+### 2. Package Dependencies
+- Keep internal package versions synchronized in `Directory.Packages.props`
+- Use conditional package versions for multi-targeting:
+ ```xml
+
+
+ ```
+
+### 3. Testing Strategy
+- All builds run unit tests before packaging
+- Preview builds enable faster feedback cycles
+- Stable builds have additional validation through Azure DevOps Artifacts before NuGet Gallery
+
+### 4. Path-Based Triggers
+- Preview workflows use path filters to trigger only on relevant changes:
+ ```yaml
+ paths:
+ - 'src/services/common/Codebreaker.Data.SqlServer/**'
+ ```
+
+### 5. Artifact Management
+- Preview artifacts: 3-day retention
+- Stable artifacts: 30-day retention
+- Unique artifact names prevent conflicts
+
+## Workflow Execution Guide
+
+### Triggering Preview Builds
+1. **Automatic**: Push changes to main branch in monitored paths
+2. **Manual**: Use "Run workflow" button on GitHub Actions tab
+
+### Triggering Stable Builds
+1. Navigate to GitHub Actions → Select stable workflow (e.g., "SqlServer stable lib")
+2. Click "Run workflow" button
+3. Confirm deployment to production environments
+
+### Monitoring Builds
+- Check GitHub Actions tab for build status
+- Review Azure DevOps Artifacts for package availability
+- Verify NuGet Gallery for stable package publication
+
+## Troubleshooting
+
+### Common Issues
+
+#### Build Failures
+- **Deterministic build issues**: Ensure all source files are committed
+- **Package reference errors**: Verify `Directory.Packages.props` contains all required packages
+- **Multi-targeting issues**: Check conditional package references
+
+#### Deployment Failures
+- **Azure DevOps authentication**: Verify PAT token permissions
+- **NuGet Gallery publishing**: Check API key validity and package metadata
+- **Duplicate packages**: Use `--skip-duplicate` flag (already configured)
+
+#### Version Conflicts
+- **Preview version conflicts**: Increase version offset in workflow
+- **Stable version conflicts**: Update base version in project file
+
+### Debug Commands
+
+```bash
+# Local package creation (preview)
+dotnet pack --version-suffix preview.1.123 -c Release src/services/common/Codebreaker.Data.SqlServer/Codebreaker.Data.SqlServer.csproj
+
+# Local package creation (stable)
+dotnet pack -c Release src/services/common/Codebreaker.Data.SqlServer/Codebreaker.Data.SqlServer.csproj
+
+# Test package installation
+dotnet add package CNinnovation.Codebreaker.SqlServer --version 3.8.0-preview.1.123 --source https://pkgs.dev.azure.com/...
+```
+
+## Integration with Development Workflow
+
+### For Library Developers
+1. **Development**: Work on feature branches
+2. **Integration**: Merge to main branch → Automatic preview build
+3. **Testing**: Use preview packages in dependent projects
+4. **Release**: Trigger stable build when ready for production
+
+### For Library Consumers
+1. **Development**: Use preview packages from Azure DevOps Artifacts
+2. **Production**: Use stable packages from NuGet Gallery
+3. **Testing**: Pin specific preview versions for reproducible builds
+
+## Future Enhancements
+
+### Planned Improvements
+- **Automated release notes** generation from Git history
+- **Package vulnerability scanning** integration
+- **Performance regression testing** for library updates
+- **Automated dependency updates** with Dependabot
+- **Package usage analytics** and deprecation warnings
+
+### Environment-Specific Deployments
+- **Development Environment**: Auto-deploy preview packages
+- **Staging Environment**: Manual promotion of stable candidates
+- **Production Environment**: Stable packages only with approval gates
+
+This documentation provides a comprehensive guide for managing NuGet packages in the Codebreaker Backend solution, ensuring reliable and efficient package distribution for both development and production scenarios.
\ No newline at end of file
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index f763591..cfe5051 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -17,4 +17,16 @@
3.8.0
+
+
+
+ true
+ true
+ true
+ embedded
+ true
+
+ $(MSBuildProjectDirectory)=/
+ false
+
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index 0afbd22..f49c897 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -29,17 +29,20 @@
+
+
+
@@ -48,6 +51,7 @@
+
@@ -63,6 +67,7 @@
+
@@ -71,6 +76,7 @@
+
@@ -91,6 +97,7 @@
+
@@ -99,6 +106,7 @@
+
@@ -109,9 +117,11 @@
+
+
@@ -119,12 +129,14 @@
+
+
diff --git a/src/clients/Codebreaker.GameAPIs.Client/Codebreaker.GameAPIs.Client.csproj b/src/clients/Codebreaker.GameAPIs.Client/Codebreaker.GameAPIs.Client.csproj
index 6ea10ce..aa6fe25 100644
--- a/src/clients/Codebreaker.GameAPIs.Client/Codebreaker.GameAPIs.Client.csproj
+++ b/src/clients/Codebreaker.GameAPIs.Client/Codebreaker.GameAPIs.Client.csproj
@@ -16,7 +16,6 @@
readme.md
codebreaker.jpeg
3.9.0
- false
true
@@ -25,13 +24,8 @@
-
-
-
-
-
-
-
+
+
diff --git a/src/services/common/Codebreaker.Data.Cosmos/Codebreaker.Data.Cosmos.csproj b/src/services/common/Codebreaker.Data.Cosmos/Codebreaker.Data.Cosmos.csproj
index 320e2d6..05c0af1 100644
--- a/src/services/common/Codebreaker.Data.Cosmos/Codebreaker.Data.Cosmos.csproj
+++ b/src/services/common/Codebreaker.Data.Cosmos/Codebreaker.Data.Cosmos.csproj
@@ -18,8 +18,8 @@
-
-
+
+
diff --git a/src/services/common/Codebreaker.Data.Postgres/Codebreaker.Data.Postgres.csproj b/src/services/common/Codebreaker.Data.Postgres/Codebreaker.Data.Postgres.csproj
index ca5a580..dba8c58 100644
--- a/src/services/common/Codebreaker.Data.Postgres/Codebreaker.Data.Postgres.csproj
+++ b/src/services/common/Codebreaker.Data.Postgres/Codebreaker.Data.Postgres.csproj
@@ -19,17 +19,10 @@
-
+
+
-
-
-
-
-
-
-
-
diff --git a/src/services/common/Codebreaker.Data.Postgres/Directory.Packages.props b/src/services/common/Codebreaker.Data.Postgres/Directory.Packages.props
deleted file mode 100644
index 8a51652..0000000
--- a/src/services/common/Codebreaker.Data.Postgres/Directory.Packages.props
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
- false
-
-
-
-
diff --git a/src/services/common/Codebreaker.Data.SqlServer.Tests/Codebreaker.Data.SqlServer.Tests.csproj b/src/services/common/Codebreaker.Data.SqlServer.Tests/Codebreaker.Data.SqlServer.Tests.csproj
index d77eac6..08ced73 100644
--- a/src/services/common/Codebreaker.Data.SqlServer.Tests/Codebreaker.Data.SqlServer.Tests.csproj
+++ b/src/services/common/Codebreaker.Data.SqlServer.Tests/Codebreaker.Data.SqlServer.Tests.csproj
@@ -10,13 +10,13 @@
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/src/services/common/Codebreaker.Data.SqlServer/Codebreaker.Data.SqlServer.csproj b/src/services/common/Codebreaker.Data.SqlServer/Codebreaker.Data.SqlServer.csproj
index d9bb333..11dc437 100644
--- a/src/services/common/Codebreaker.Data.SqlServer/Codebreaker.Data.SqlServer.csproj
+++ b/src/services/common/Codebreaker.Data.SqlServer/Codebreaker.Data.SqlServer.csproj
@@ -19,8 +19,8 @@
-
-
+
+
diff --git a/src/services/common/Codebreaker.GameAPIs.Analyzers/Codebreaker.Analyzers.csproj b/src/services/common/Codebreaker.GameAPIs.Analyzers/Codebreaker.Analyzers.csproj
index 6bc637b..71219b0 100644
--- a/src/services/common/Codebreaker.GameAPIs.Analyzers/Codebreaker.Analyzers.csproj
+++ b/src/services/common/Codebreaker.GameAPIs.Analyzers/Codebreaker.Analyzers.csproj
@@ -17,6 +17,9 @@
readme.md
codebreaker.jpeg
true
+
+ $(NoWarn);NU5017
+ false