@@ -2,170 +2,120 @@ name: .NET Workflow
22
33on :
44 push :
5- branches :
6- - main
7- - develop
5+ branches : [main, develop]
6+ paths-ignore : ['**.md', '.github/ISSUE_TEMPLATE/**', '.github/pull_request_template.md']
87 pull_request :
8+ paths-ignore : ['**.md', '.github/ISSUE_TEMPLATE/**', '.github/pull_request_template.md']
99 schedule :
10- - cron : " 0 23 * * *"
10+ - cron : " 0 23 * * *" # Daily at 11 PM UTC
1111
1212concurrency :
1313 group : ${{ github.workflow }}-${{ github.ref }}
14+ cancel-in-progress : true
1415
15- permissions :
16- packages : write
17- contents : write
16+ # Default permissions
17+ permissions : read-all
1818
1919env :
20- OUTPUT_PATH : ' output'
21- STAGING_PATH : ' staging'
22- DOTNET_VERSION : ' 9.0'
20+ DOTNET_VERSION : ' 9.0' # Only needed for actions/setup-dotnet
2321
2422jobs :
25- dotnet :
26- name : .NET Workflow
23+ build :
24+ name : Build, Test & Release
2725 runs-on : windows-latest
26+ timeout-minutes : 15
27+ permissions :
28+ contents : write # For creating releases and committing metadata
29+ packages : write # For publishing packages
30+
31+ outputs :
32+ version : ${{ steps.pipeline.outputs.version }}
33+ release_hash : ${{ steps.pipeline.outputs.release_hash }}
34+ should_release : ${{ steps.pipeline.outputs.should_release }}
35+
2836 steps :
29- - uses : actions/checkout@v4
37+ - name : Checkout Repository
38+ uses : actions/checkout@v4
3039 with :
40+ fetch-depth : 0 # Full history for versioning
41+ fetch-tags : true
42+ lfs : true
3143 submodules : recursive
3244 persist-credentials : true
33- lfs : true
34- fetch-tags : true
3545
36- - name : Fetch tags
37- shell : pwsh
38- run : |
39- git fetch --prune --unshallow --tags
40-
41- $global:LASTEXITCODE = 0
46+ - name : Setup .NET SDK ${{ env.DOTNET_VERSION }}
47+ uses : actions/setup-dotnet@v4
48+ with :
49+ dotnet-version : ${{ env.DOTNET_VERSION }}.x
50+ cache : true
51+ cache-dependency-path : ' **/*.csproj '
4252
43- - name : Configure Environment
53+ - name : Run PSBuild Pipeline
54+ id : pipeline
4455 shell : pwsh
4556 env :
4657 GH_TOKEN : ${{ github.token }}
4758 run : |
48- $IS_FORK = (gh repo view --json isFork | ConvertFrom-Json).isFork
49- $IS_MAIN = "${{ github.ref }}" -eq "refs/heads/main"
50- $IS_TAGGED = (git show-ref --tags -d | Out-String).Contains("${{ github.sha }}")
51- $SHOULD_RELEASE = ($IS_MAIN -AND -NOT $IS_TAGGED -AND -NOT $IS_FORK)
52- $USE_DOTNET_SCRIPT = (Get-ChildItem -Recurse -Filter *.csx).Count -gt 0
53- $PACKAGE_PATTERN = Join-Path -Path "${{ github.workspace }}" -ChildPath "${{ env.STAGING_PATH }}" -AdditionalChildPath "*.nupkg"
54- $SYMBOLS_PATTERN = Join-Path -Path "${{ github.workspace }}" -ChildPath "${{ env.STAGING_PATH }}" -AdditionalChildPath "*.snupkg"
55- $APPLICATION_PATTERN = Join-Path -Path "${{ github.workspace }}" -ChildPath "${{ env.STAGING_PATH }}" -AdditionalChildPath "*.zip"
56-
57- $BUILD_ARGS = ""
58- $BUILD_ARGS += $USE_DOTNET_SCRIPT ? "-maxCpuCount:1" : ""
59-
60- "IS_FORK=$IS_FORK" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
61- "IS_MAIN=$IS_MAIN" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
62- "IS_TAGGED=$IS_TAGGED" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
63- "SHOULD_RELEASE=$SHOULD_RELEASE" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
64- "USE_DOTNET_SCRIPT=$USE_DOTNET_SCRIPT" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
65- "PACKAGE_PATTERN=$PACKAGE_PATTERN" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
66- "SYMBOLS_PATTERN=$SYMBOLS_PATTERN" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
67- "APPLICATION_PATTERN=$APPLICATION_PATTERN" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
68- "BUILD_ARGS=$BUILD_ARGS" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
69-
70- Write-Host "IS_FORK: $IS_FORK"
71- Write-Host "IS_MAIN: $IS_MAIN"
72- Write-Host "IS_TAGGED: $IS_TAGGED"
73- Write-Host "SHOULD_RELEASE: $SHOULD_RELEASE"
74- Write-Host "USE_DOTNET_SCRIPT: $USE_DOTNET_SCRIPT"
75- Write-Host "PACKAGE_PATTERN: $PACKAGE_PATTERN"
76- Write-Host "SYMBOLS_PATTERN: $SYMBOLS_PATTERN"
77- Write-Host "APPLICATION_PATTERN: $APPLICATION_PATTERN"
78- Write-Host "BUILD_ARGS: $BUILD_ARGS"
79-
80- $global:LASTEXITCODE = 0
81-
82- - name : Make Version
83- if : ${{ env.SHOULD_RELEASE == 'True' }}
84- shell : pwsh
85- run : scripts/make-version.ps1 "${{ github.sha }}"
59+ # Import the PSBuild module
60+ Import-Module ${{ github.workspace }}/scripts/PSBuild.psm1
61+
62+ # Get build configuration
63+ $buildConfig = Get-BuildConfiguration `
64+ -ServerUrl "${{ github.server_url }}" `
65+ -GitRef "${{ github.ref }}" `
66+ -GitSha "${{ github.sha }}" `
67+ -GitHubOwner "${{ github.repository_owner }}" `
68+ -GitHubRepo "${{ github.repository }}" `
69+ -GithubToken "${{ github.token }}" `
70+ -NuGetApiKey "${{ secrets.NUGET_KEY }}" `
71+ -WorkspacePath "${{ github.workspace }}" `
72+ -ExpectedOwner "ktsu-dev" `
73+ -ChangelogFile "CHANGELOG.md" `
74+ -AssetPatterns @("staging/*.nupkg", "staging/*.zip")
75+
76+ if (-not $buildConfig.Success) {
77+ throw $buildConfig.Error
78+ }
8679
87- - name : Make License
88- if : ${{ env.SHOULD_RELEASE == 'True' }}
89- shell : pwsh
90- run : scripts/make-license.ps1 "${{ github.server_url }}" "${{ github.repository_owner }}" "${{ github.repository }}"
80+ # Run the complete CI/CD pipeline
81+ $result = Invoke-CIPipeline `
82+ -BuildConfiguration $buildConfig.Data
9183
92- - name : Make Changelog
93- if : ${{ env.SHOULD_RELEASE == 'True' }}
94- shell : pwsh
95- run : scripts/make-changelog.ps1 "${{ env.VERSION }}" "${{ github.sha }}"
84+ if (-not $result.Success) {
85+ Write-Information "CI/CD pipeline failed: $($result.Error)" -Tags "Invoke-CIPipeline"
86+ Write-Information "Stack Trace: $($result.StackTrace)" -Tags "Invoke-CIPipeline"
87+ Write-Information "Build Configuration: $($buildConfig.Data | ConvertTo-Json -Depth 10)" -Tags "Invoke-CIPipeline"
88+ throw $result.Error
89+ }
9690
97- - name : Commit Metadata
98- if : ${{ env.SHOULD_RELEASE == 'True' }}
99- shell : pwsh
100- run : scripts/commit-metadata.ps1
91+ # Set outputs for GitHub Actions from build configuration
92+ "version=$($buildConfig.Data.Version)" >> $env:GITHUB_OUTPUT
93+ "release_hash=$($buildConfig.Data.ReleaseHash)" >> $env:GITHUB_OUTPUT
94+ "should_release=$($buildConfig.Data.ShouldRelease)" >> $env:GITHUB_OUTPUT
10195
102- - name : Setup .NET Core SDK
103- uses : actions/setup-dotnet@v4
96+ - name : Upload Coverage Report
97+ uses : actions/upload-artifact@v4
98+ if : always()
10499 with :
105- dotnet-version : |
106- ${{ env.DOTNET_VERSION }}.x
107-
108- - name : Install dotnet-script
109- if : ${{ env.USE_DOTNET_SCRIPT == 'True' }}
110- shell : pwsh
111- run : dotnet tool install -g dotnet-script
112-
113- - name : Build
114- shell : pwsh
115- run : dotnet build --configuration Release --verbosity normal --no-incremental ${{ env.BUILD_ARGS }}
100+ name : coverage-report
101+ path : ./coverage
102+ retention-days : 7
103+
104+ security :
105+ name : Security Scanning
106+ needs : build
107+ if : needs.build.outputs.should_release == 'true'
108+ runs-on : windows-latest
109+ timeout-minutes : 10
110+ permissions :
111+ id-token : write # For dependency submission
112+ contents : write # For dependency submission
116113
117- - name : Test
118- shell : pwsh
119- run : dotnet test -m:1 --configuration Release --verbosity normal --no-build
114+ steps :
115+ - name : Checkout Release Commit
116+ uses : actions/checkout@v4
117+ with :
118+ ref : ${{ needs.build.outputs.release_hash }}
120119
121120 - name : Detect Dependencies
122- if : ${{ env.SHOULD_RELEASE == 'True' }}
123121 uses : advanced-security/component-detection-dependency-submission-action@v0.0.2
124-
125- - name : Package Libraries
126- if : ${{ env.SHOULD_RELEASE == 'True' }}
127- shell : pwsh
128- run : dotnet pack --configuration Release --output ${{ github.workspace }}/${{ env.STAGING_PATH }}
129-
130- - name : Package Applications
131- if : ${{ env.SHOULD_RELEASE == 'True' }}
132- shell : pwsh
133- run : |
134- if (Test-Path ${{ github.workspace }}/${{ env.OUTPUT_PATH }}) {
135- Remove-Item -Recurse -Force ${{ github.workspace }}/${{ env.OUTPUT_PATH }}
136- }
137- Get-ChildItem -Recurse -Filter *.csproj | ForEach-Object {
138- $csproj = $_
139- $projName = [System.IO.Path]::GetFileNameWithoutExtension($csproj)
140- $outDir = "${{ github.workspace }}/${{ env.OUTPUT_PATH }}/$projName"
141- $stageDir = "${{ github.workspace }}/${{ env.STAGING_PATH }}"
142- $stageFile = "$stageDir/$projName-${{ env.VERSION }}.zip"
143- New-Item -Path $outDir -ItemType Directory -Force
144- New-Item -Path $stageDir -ItemType Directory -Force
145- dotnet publish $csproj --no-build --configuration Release --framework net${{ env.DOTNET_VERSION }} --output $outDir
146- Compress-Archive -Path $outDir/* -DestinationPath $stageFile
147- }
148-
149- - name : Publish Libraries to GitHub
150- if : ${{ env.SHOULD_RELEASE == 'True' && hashFiles(env.PACKAGE_PATTERN) != '' }}
151- shell : pwsh
152- run : dotnet nuget push ${{ env.PACKAGE_PATTERN }} --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json --skip-duplicate
153-
154- - name : Publish Libraries to NuGet
155- if : ${{ env.SHOULD_RELEASE == 'True' && hashFiles(env.PACKAGE_PATTERN) != '' }}
156- shell : pwsh
157- run : dotnet nuget push ${{ env.PACKAGE_PATTERN }} --api-key ${{ secrets.NUGET_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
158-
159- - name : Release
160- if : ${{ env.SHOULD_RELEASE == 'True' }}
161- uses : ncipollo/release-action@v1
162- with :
163- artifacts : " ${{ env.PACKAGE_PATTERN }},${{ env.SYMBOLS_PATTERN }},${{ env.APPLICATION_PATTERN }}"
164- tag : v${{ env.VERSION }}
165- commit : ${{ env.RELEASE_HASH }}
166- allowUpdates : false
167- skipIfReleaseExists : true
168- generateReleaseNotes : true
169- bodyFile : CHANGELOG.md
170- replacesArtifacts : false
171- makeLatest : true
0 commit comments