1- // Copyright (c) Duende Software. All rights reserved.
1+ // Copyright (c) Duende Software. All rights reserved.
22// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
33
44using Logicality . GitHub . Actions . Workflow ;
3333 GenerateReleaseWorkflow ( component ) ;
3434}
3535
36+ GenerateUploadTestResultsWorkflow ( ) ;
37+
38+
3639void GenerateCiWorkflow ( Component component )
3740{
38- var workflow = new Workflow ( $ " { component . Name } /ci" ) ;
41+ var workflow = new Workflow ( component . CiWorkflowName ) ;
3942 var paths = new [ ]
4043 {
4144 $ ".github/workflows/{ component . Name } -**",
@@ -49,7 +52,7 @@ void GenerateCiWorkflow(Component component)
4952 . Push ( )
5053 . Paths ( paths ) ;
5154 workflow . On
52- . PullRequestTarget ( )
55+ . PullRequest ( )
5356 . Paths ( paths ) ;
5457
5558 workflow . EnvDefaults ( ) ;
@@ -76,10 +79,10 @@ void GenerateCiWorkflow(Component component)
7679
7780 foreach ( var testProject in component . Tests )
7881 {
79- job . StepTestAndReport ( component . Name , testProject ) ;
82+ job . StepTest ( component . Name , testProject ) ;
8083 }
8184
82- job . StepInstallCACerts ( ) ;
85+ job . StepUploadTestResultsAsArtifact ( component ) ;
8386
8487 job . StepToolRestore ( ) ;
8588
@@ -90,8 +93,6 @@ void GenerateCiWorkflow(Component component)
9093
9194 job . StepSign ( ) ;
9295
93- job . StepPush ( "MyGet" , "https://www.myget.org/F/duende_identityserver/api/v2/package" , "MYGET" ) ;
94-
9596 job . StepPush ( "GitHub" , "https://nuget.pkg.github.com/DuendeSoftware/index.json" , "GITHUB_TOKEN" )
9697 . Env ( ( "GITHUB_TOKEN" , contexts . Secrets . GitHubToken ) ,
9798 ( "NUGET_AUTH_TOKEN" , contexts . Secrets . GitHubToken ) ) ;
@@ -104,7 +105,7 @@ void GenerateCiWorkflow(Component component)
104105
105106void GenerateReleaseWorkflow ( Component component )
106107{
107- var workflow = new Workflow ( $ " { component . Name } /release" ) ;
108+ var workflow = new Workflow ( component . ReleaseWorkflowName ) ;
108109
109110 workflow . On
110111 . WorkflowDispatch ( )
@@ -138,16 +139,14 @@ git config --global user.name ""Duende Software GitHub Bot""
138139git tag -a { component . TagPrefix } -{ contexts . Event . Input . Version } -m ""Release v{ contexts . Event . Input . Version } ""
139140git push origin { component . TagPrefix } -{ contexts . Event . Input . Version } " ) ;
140141
141- tagJob . StepInstallCACerts ( ) ;
142-
143142 foreach ( var project in component . Projects )
144143 {
145144 tagJob . StepPack ( project ) ;
146145 }
147146
148147 tagJob . StepToolRestore ( ) ;
149148
150- tagJob . StepSign ( ) ;
149+ tagJob . StepSign ( true ) ;
151150
152151 tagJob . StepPush ( "MyGet" , "https://www.myget.org/F/duende_identityserver/api/v2/package" , "MYGET" ) ;
153152
@@ -160,8 +159,7 @@ git tag -a {component.TagPrefix}-{contexts.Event.Input.Version} -m ""Release v{c
160159 var publishJob = workflow . Job ( "publish" )
161160 . Name ( "Publish to nuget.org" )
162161 . RunsOn ( GitHubHostedRunners . UbuntuLatest )
163- . Needs ( "tag" )
164- . Environment ( "nuget.org" , "" ) ;
162+ . Needs ( "tag" ) ;
165163
166164 publishJob . Step ( )
167165 . Uses ( "actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16" ) // 4.1.8
@@ -180,20 +178,55 @@ git tag -a {component.TagPrefix}-{contexts.Event.Input.Version} -m ""Release v{c
180178 WriteWorkflow ( workflow , fileName ) ;
181179}
182180
181+ void GenerateUploadTestResultsWorkflow ( )
182+ {
183+ var workflow = new Workflow ( "generate-test-reports" ) ;
184+ workflow . On
185+ . WorkflowRun ( )
186+ . Workflows ( components . Select ( x => x . CiWorkflowName ) . ToArray ( ) )
187+ . Types ( "completed" ) ;
188+
189+ var job = workflow
190+ . Job ( "report" )
191+ . Name ( "report" )
192+ . RunsOn ( GitHubHostedRunners . UbuntuLatest ) ;
193+
194+ job . Permissions (
195+ actions : Permission . Read ,
196+ contents : Permission . Read ,
197+ checks : Permission . Write ,
198+ packages : Permission . Write ) ;
199+
200+ foreach ( var component in components )
201+ {
202+ foreach ( var testProject in component . Tests )
203+ {
204+ job . StepGenerateReportFromTestArtifact ( component , testProject ) ;
205+ }
206+ }
207+
208+ var fileName = $ "generate-test-reports";
209+ WriteWorkflow ( workflow , fileName ) ;
210+ }
211+
183212void WriteWorkflow ( Workflow workflow , string fileName )
184213{
185214 var filePath = $ "../workflows/{ fileName } .yml";
186215 workflow . WriteYaml ( filePath ) ;
187216 Console . WriteLine ( $ "Wrote workflow to { filePath } ") ;
188217}
189218
190- record Component ( string Name , string [ ] Projects , string [ ] Tests , string TagPrefix ) ;
219+ record Component ( string Name , string [ ] Projects , string [ ] Tests , string TagPrefix )
220+ {
221+ public string CiWorkflowName => $ "{ Name } /ci";
222+ public string ReleaseWorkflowName => $ "{ Name } /release";
223+ }
191224
192225public static class StepExtensions
193226{
194227 public static void EnvDefaults ( this Workflow workflow )
195228 => workflow . Env (
196- ( "DOTNETT_NOLOGO " , "true" ) ,
229+ ( "DOTNET_NOLOGO " , "true" ) ,
197230 ( "DOTNET_CLI_TELEMETRY_OPTOUT" , "true" ) ) ;
198231
199232 public static void StepSetupDotNet ( this Job job )
@@ -204,41 +237,48 @@ public static void StepSetupDotNet(this Job job)
204237 public static Step IfRefMain ( this Step step )
205238 => step . If ( "github.ref == 'refs/heads/main'" ) ;
206239
207- public static void StepTestAndReport ( this Job job , string componentName , string testProject )
240+ public static void StepTest ( this Job job , string componentName , string testProject )
208241 {
209242 var path = $ "test/{ testProject } ";
210- var logFileName = "Tests .trx";
243+ var logFileName = $ " { testProject } .trx";
211244 var flags = $ "--logger \" console;verbosity=normal\" " +
212245 $ "--logger \" trx;LogFileName={ logFileName } \" " +
213246 $ "--collect:\" XPlat Code Coverage\" ";
214247 job . Step ( )
215248 . Name ( $ "Test - { testProject } ")
216249 . Run ( $ "dotnet test -c Release { path } { flags } ") ;
217250
251+ }
252+
253+ internal static void StepUploadTestResultsAsArtifact ( this Job job , Component component )
254+ {
218255 job . Step ( )
219- . Name ( $ "Test report - { testProject } ")
220- . Uses ( "dorny/test-reporter@31a54ee7ebcacc03a09ea97a7e5465a47b84aea5" ) // v1.9.1
256+ . Name ( $ "Test report")
221257 . If ( "success() || failure()" )
258+ . Uses ( "actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882" ) // 4.4.3
259+ . With (
260+ ( "name" , "test-results" ) ,
261+ ( "path" , string . Join ( Environment . NewLine , component . Tests
262+ . Select ( testProject => $ "{ component . Name } /test/{ testProject } /TestResults/{ testProject } .trx") ) ) ,
263+ ( "retention-days" , "5" ) ) ;
264+ }
265+
266+ internal static void StepGenerateReportFromTestArtifact ( this Job job , Component component , string testProject )
267+ {
268+ var path = $ "test/{ testProject } ";
269+ job . Step ( )
270+ . Name ( $ "Test report - { component . Name } - { testProject } ")
271+ . Uses ( "dorny/test-reporter@31a54ee7ebcacc03a09ea97a7e5465a47b84aea5" ) // v1.9.1
272+ . If ( $ "github.event.workflow.name == '{ component . CiWorkflowName } '")
222273 . With (
274+ ( "artifact" , "test-results" ) ,
223275 ( "name" , $ "Test Report - { testProject } ") ,
224- ( "path" , $ "{ componentName } / { path } /TestResults/ { logFileName } ") ,
276+ ( "path" , $ "{ testProject } .trx ") ,
225277 ( "reporter" , "dotnet-trx" ) ,
226278 ( "fail-on-error" , "true" ) ,
227279 ( "fail-on-empty" , "true" ) ) ;
228280 }
229281
230- // These intermediate certificates are required for signing and are not installed on the GitHub runners by default.
231- public static void StepInstallCACerts ( this Job job )
232- => job . Step ( )
233- . Name ( "Install Sectigo CodeSiging CA certificates" )
234- . WorkingDirectory ( ".github/workflows" )
235- . Run ( """
236- sudo apt-get update
237- sudo apt-get install -y ca-certificates
238- sudo cp SectigoPublicCodeSigningRootCrossAAA.crt /usr/local/share/ca-certificates/
239- sudo update-ca-certificates
240- """ ) ;
241-
242282 public static void StepToolRestore ( this Job job )
243283 => job . Step ( )
244284 . Name ( "Tool restore" )
@@ -252,23 +292,33 @@ public static void StepPack(this Job job, string project)
252292 . Run ( $ "dotnet pack -c Release { path } -o artifacts") ;
253293 }
254294
255- public static void StepSign ( this Job job )
295+ public static void StepSign ( this Job job , bool always = false )
256296 {
257- var flags = "--file-digest sha256 " +
258- "--timestamp-rfc3161 http://timestamp.digicert.com " +
259- "--azure-key-vault-url https://duendecodesigning.vault.azure.net/ " +
260- "--azure-key-vault-client-id 18e3de68-2556-4345-8076-a46fad79e474 " +
261- "--azure-key-vault-tenant-id ed3089f0-5401-4758-90eb-066124e2d907 " +
262- "--azure-key-vault-client-secret ${{ secrets.SignClientSecret }} " +
263- "--azure-key-vault-certificate CodeSigning" ;
264- job . Step ( )
265- . Name ( "Sign packages" )
266- . Run ( $ """
267- for file in artifacts/*.nupkg; do
268- dotnet NuGetKeyVaultSignTool sign "$file" { flags }
269- done
270- """ ) ;
297+ var flags = "--file-digest sha256 " +
298+ "--timestamp-rfc3161 http://timestamp.digicert.com " +
299+ "--azure-key-vault-url https://duendecodesigninghsm.vault.azure.net/ " +
300+ "--azure-key-vault-client-id 18e3de68-2556-4345-8076-a46fad79e474 " +
301+ "--azure-key-vault-tenant-id ed3089f0-5401-4758-90eb-066124e2d907 " +
302+ "--azure-key-vault-client-secret ${{ secrets.SignClientSecret }} " +
303+ "--azure-key-vault-certificate NuGetPackageSigning" ;
304+ var step = job . Step ( )
305+ . Name ( "Sign packages" ) ;
306+ if ( ! always )
307+ {
308+ step = step . IfGithubEventIsPush ( ) ;
309+ }
310+ step . Run ( $ """
311+ for file in artifacts/*.nupkg; do
312+ dotnet NuGetKeyVaultSignTool sign "$file" { flags }
313+ done
314+ """ ) ;
271315 }
316+ /// <summary>
317+ /// Only run this if the build is triggered on a branch IN the same repo
318+ /// this means it's from a trusted contributor.
319+ /// </summary>
320+ public static Step IfGithubEventIsPush ( this Step step )
321+ => step . If ( "github.event_name == 'push'" ) ;
272322
273323 public static Step StepPush ( this Job job , string destination , string sourceUrl , string secretName )
274324 {
@@ -284,7 +334,7 @@ public static void StepUploadArtifacts(this Job job, string componentName)
284334 var path = $ "{ componentName } /artifacts/*.nupkg";
285335 job . Step ( )
286336 . Name ( "Upload Artifacts" )
287- . IfRefMain ( )
337+ . IfGithubEventIsPush ( )
288338 . Uses ( "actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882" ) // 4.4.3
289339 . With (
290340 ( "name" , "artifacts" ) ,
@@ -326,4 +376,4 @@ public class EventsInputContext() : Context("github.event.inputs")
326376 {
327377 public string Version => Expression ( $ "{ Name } .version") ;
328378 }
329- }
379+ }
0 commit comments