Skip to content

.NET Workflow

.NET Workflow #446

Workflow file for this run

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