.NET Workflow #446
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: .NET Workflow | |
| on: | |
| push: | |
| branches: [main, develop] | |
| paths-ignore: | |
| ["**.md", ".github/ISSUE_TEMPLATE/**", ".github/pull_request_template.md"] | |
| pull_request: | |
| paths-ignore: | |
| ["**.md", ".github/ISSUE_TEMPLATE/**", ".github/pull_request_template.md"] | |
| schedule: | |
| - cron: "0 23 * * *" # Daily at 11 PM UTC | |
| workflow_dispatch: # Allow manual triggers | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| # Default permissions | |
| permissions: read-all | |
| env: | |
| DOTNET_VERSION: "9.0" # Only needed for actions/setup-dotnet | |
| jobs: | |
| build: | |
| name: Build, Test & Release | |
| runs-on: windows-latest | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: write # For creating releases and committing metadata | |
| packages: write # For publishing packages | |
| outputs: | |
| version: ${{ steps.pipeline.outputs.version }} | |
| release_hash: ${{ steps.pipeline.outputs.release_hash }} | |
| should_release: ${{ steps.pipeline.outputs.should_release }} | |
| skipped_release: ${{ steps.pipeline.outputs.skipped_release }} | |
| steps: | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: 17 | |
| distribution: "zulu" # Alternative distribution options are available. | |
| - name: Checkout Repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Full history for versioning | |
| fetch-tags: true | |
| lfs: true | |
| submodules: recursive | |
| persist-credentials: true | |
| - name: Setup .NET SDK ${{ env.DOTNET_VERSION }} | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }}.x | |
| cache: true | |
| cache-dependency-path: "**/*.csproj" | |
| - name: Cache SonarQube Cloud packages | |
| if: ${{ env.SONAR_TOKEN != '' }} | |
| uses: actions/cache@v4 | |
| env: | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| with: | |
| path: ~\sonar\cache | |
| key: ${{ runner.os }}-sonar | |
| restore-keys: ${{ runner.os }}-sonar | |
| - name: Cache SonarQube Cloud scanner | |
| if: ${{ env.SONAR_TOKEN != '' }} | |
| id: cache-sonar-scanner | |
| uses: actions/cache@v4 | |
| env: | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| with: | |
| path: .\.sonar\scanner | |
| key: ${{ runner.os }}-sonar-scanner | |
| restore-keys: ${{ runner.os }}-sonar-scanner | |
| - name: Install SonarQube Cloud scanner | |
| if: ${{ env.SONAR_TOKEN != '' && steps.cache-sonar-scanner.outputs.cache-hit != 'true' }} | |
| env: | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| shell: powershell | |
| run: | | |
| New-Item -Path .\.sonar\scanner -ItemType Directory | |
| dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner | |
| - name: Begin SonarQube | |
| if: ${{ env.SONAR_TOKEN != '' }} | |
| env: | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| shell: powershell | |
| run: | | |
| .\.sonar\scanner\dotnet-sonarscanner begin /k:"${{ github.repository_owner }}_${{ github.event.repository.name }}" /o:"${{ github.repository_owner }}" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="coverage/coverage.opencover.xml" /d:sonar.coverage.exclusions="**/*Test*.cs,**/*.Tests.cs,**/*.Tests/**/*,**/obj/**/*,**/*.dll" /d:sonar.cs.vstest.reportsPaths="coverage/TestResults/**/*.trx" | |
| - name: Run PSBuild Pipeline | |
| id: pipeline | |
| shell: pwsh | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # Import the PSBuild module | |
| Import-Module ${{ github.workspace }}/scripts/PSBuild.psm1 | |
| # Get build configuration | |
| $buildConfig = Get-BuildConfiguration ` | |
| -ServerUrl "${{ github.server_url }}" ` | |
| -GitRef "${{ github.ref }}" ` | |
| -GitSha "${{ github.sha }}" ` | |
| -GitHubOwner "${{ github.repository_owner }}" ` | |
| -GitHubRepo "${{ github.repository }}" ` | |
| -GithubToken "${{ github.token }}" ` | |
| -NuGetApiKey "${{ secrets.NUGET_KEY }}" ` | |
| -KtsuPackageKey "${{ secrets.KTSU_PACKAGE_KEY }}" ` | |
| -WorkspacePath "${{ github.workspace }}" ` | |
| -ExpectedOwner "ktsu-dev" ` | |
| -ChangelogFile "CHANGELOG.md" ` | |
| -AssetPatterns @("staging/*.nupkg", "staging/*.zip") | |
| if (-not $buildConfig.Success) { | |
| throw $buildConfig.Error | |
| } | |
| # Run the complete CI/CD pipeline | |
| $result = Invoke-CIPipeline ` | |
| -BuildConfiguration $buildConfig.Data | |
| if (-not $result.Success) { | |
| Write-Information "CI/CD pipeline failed: $($result.Error)" -Tags "Invoke-CIPipeline" | |
| Write-Information "Stack Trace: $($result.StackTrace)" -Tags "Invoke-CIPipeline" | |
| Write-Information "Build Configuration: $($buildConfig.Data | ConvertTo-Json -Depth 10)" -Tags "Invoke-CIPipeline" | |
| throw $result.Error | |
| } | |
| # Set outputs for GitHub Actions from build configuration and pipeline result | |
| # Use pipeline result values when available (for skipped releases), otherwise use buildConfig | |
| if ($result.Data.SkippedRelease) { | |
| "version=$($result.Data.Version)" >> $env:GITHUB_OUTPUT | |
| "release_hash=$($result.Data.ReleaseHash)" >> $env:GITHUB_OUTPUT | |
| "should_release=$($buildConfig.Data.ShouldRelease)" >> $env:GITHUB_OUTPUT | |
| "skipped_release=true" >> $env:GITHUB_OUTPUT | |
| } else { | |
| "version=$($buildConfig.Data.Version)" >> $env:GITHUB_OUTPUT | |
| "release_hash=$($buildConfig.Data.ReleaseHash)" >> $env:GITHUB_OUTPUT | |
| "should_release=$($buildConfig.Data.ShouldRelease)" >> $env:GITHUB_OUTPUT | |
| # Check for skipped release from buildConfig as fallback | |
| if ($buildConfig.Data.SkippedRelease) { | |
| "skipped_release=true" >> $env:GITHUB_OUTPUT | |
| } | |
| } | |
| - name: End SonarQube | |
| if: env.SONAR_TOKEN != '' && steps.pipeline.outputs.skipped_release != 'true' | |
| env: | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| shell: powershell | |
| run: | | |
| .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" | |
| - name: Upload Coverage Report | |
| uses: actions/upload-artifact@v4 | |
| if: always() && steps.pipeline.outputs.skipped_release != 'true' | |
| with: | |
| name: coverage-report | |
| path: | | |
| ./coverage/* | |
| retention-days: 7 | |
| winget: | |
| name: Update Winget Manifests | |
| needs: build | |
| if: needs.build.outputs.should_release == 'true' && needs.build.outputs.skipped_release != 'true' | |
| runs-on: windows-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout Release Commit | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.build.outputs.release_hash }} | |
| fetch-depth: 0 # Full history for better auto-detection | |
| - name: Setup .NET SDK ${{ env.DOTNET_VERSION }} | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }}.x | |
| - name: Update Winget Manifests | |
| shell: pwsh | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # Use enhanced script with auto-detection capabilities | |
| Write-Host "Updating winget manifests for version ${{ needs.build.outputs.version }}" | |
| .\scripts\update-winget-manifests.ps1 -Version "${{ needs.build.outputs.version }}" | |
| - name: Upload Updated Manifests | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: winget-manifests-${{ needs.build.outputs.version }} | |
| path: winget/*.yaml | |
| retention-days: 30 | |
| security: | |
| name: Security Scanning | |
| needs: build | |
| if: needs.build.outputs.should_release == 'true' && needs.build.outputs.skipped_release != 'true' | |
| runs-on: windows-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| id-token: write # For dependency submission | |
| contents: write # For dependency submission | |
| steps: | |
| - name: Checkout Release Commit | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.build.outputs.release_hash }} | |
| - name: Detect Dependencies | |
| uses: advanced-security/component-detection-dependency-submission-action@v0.0.2 |