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