1
1
using Logicality . GitHub . Actions . Workflow ;
2
- using System . IO ;
2
+ using System . ComponentModel ;
3
+
4
+ Component [ ] components = [
5
+ new ( "ignore-this" ,
6
+ [ "IgnoreThis" ] ,
7
+ [ "IgnoreThis.Tests" ] ) ,
8
+
9
+ new ( "access-token-management" ,
10
+ [ "AccessTokenManagement" , "AccessTokenManagement.OpenIdConnect" ] ,
11
+ [ "AccessTokenManagement.Tests" ] ) ,
12
+
13
+ new ( "identity-model" ,
14
+ [ "IdentityModel" ] ,
15
+ [ "IdentityModel.Tests" ] ) ,
16
+
17
+ new ( "identity-model-oidc-client" ,
18
+ [ "IdentityModel.OidcClient" , "IdentityModel.OidcClient.DPoP" , "IdentityModel.OidcClient.IdentityTokenValidator" ] ,
19
+ [ "IdentityModel.OidcClient.Tests" , "IdentityModel.OidcClient.DPoP.Tests" , "IdentityModel.OidcClient.IdentityTokenValidator.Tests" ] )
20
+ ] ;
3
21
4
22
void WriteWorkflow ( Workflow workflow , string fileName )
5
23
{
@@ -8,45 +26,140 @@ void WriteWorkflow(Workflow workflow, string fileName)
8
26
Console . WriteLine ( $ "Wrote workflow to { filePath } ") ;
9
27
}
10
28
11
-
12
- Component [ ] components = [
13
- new ( "ignore-this" , [ "IgnoreThis" ] , [ "IgnoreThis.Tests" ] ) ,
14
- ] ;
15
-
16
- ( string Key , string Value ) EnvSecret ( string key ) => ( key , $ "${{secrets.{ key } }}") ;
17
-
18
-
19
- foreach ( var component in components )
29
+ void GenerateCiWorkflow ( Component component )
20
30
{
21
- var workflow = new Workflow ( $ "{ component . Name } - ci") ;
22
- var paths = new [ ] { $ ".github/workflows/{ component . Name } -ci ", $ "src/{ component . Name } /**" } ;
31
+ var workflow = new Workflow ( $ "{ component . Name } / ci") ;
32
+ var paths = new [ ] { $ ".github/workflows/{ component . Name } -** ", $ "src/{ component . Name } /**" } ;
23
33
24
- workflow . On . WorkflowDispatch ( ) ;
34
+ workflow . On
35
+ . WorkflowDispatch ( ) ;
25
36
workflow . On
26
37
. Push ( )
27
- . Branches ( "main" ) ;
38
+ . Paths ( paths ) ;
28
39
workflow . On
29
40
. PullRequest ( )
30
41
. Paths ( paths ) ;
31
42
32
- workflow . Env (
33
- ( "DOTNETT_NOLOGO" , "true" ) ,
34
- ( "DOTNET_CLI_TELEMETRY_OPTOUT" , "true" ) ) ;
43
+ workflow . EnvDefaults ( ) ;
35
44
36
45
var job = workflow
37
46
. Job ( "build" )
38
47
. Name ( "Build" )
39
48
. RunsOn ( GitHubHostedRunners . UbuntuLatest )
49
+ . Defaults ( ) . Run ( "bash" , component . Name )
50
+ . Job ;
51
+
52
+ job . Step ( )
53
+ . ActionsCheckout ( ) ;
54
+
55
+ job . StepSetupDotNet ( ) ;
56
+
57
+ foreach ( var testProject in component . Tests )
58
+ {
59
+ job . StepTestAndReport ( component . Name , testProject ) ;
60
+ }
61
+
62
+ job . StepInstallCACerts ( ) ;
63
+
64
+ job . StepToolRestore ( ) ;
65
+
66
+ foreach ( var project in component . Projects )
67
+ {
68
+ job . StepPack ( component . Name , project ) ;
69
+ }
70
+
71
+ job . StepSign ( ) ;
72
+
73
+ job . StepPush ( "MyGet" , "https://www.myget.org/F/duende_identityserver/api/v2/package" , "MYGET" ) ;
74
+
75
+ job . StepPush ( "GitHub" , "https://nuget.pkg.github.com/DuendeSoftware/index.json" , "GITHUB_TOKEN" )
76
+ . Env ( ( "GITHUB_TOKEN" , "${{ secrets.GITHUB_TOKEN }}" ) ,
77
+ ( "NUGET_AUTH_TOKEN" , "${{ secrets.GITHUB_TOKEN }}" ) ) ;
78
+
79
+ job . StepUploadArtifacts ( component . Name ) ;
80
+
81
+ var fileName = $ "{ component . Name } -ci";
82
+ WriteWorkflow ( workflow , fileName ) ;
83
+ }
84
+
85
+ void GenerateReleaseWorkflow ( Component component )
86
+ {
87
+ var workflow = new Workflow ( $ "{ component . Name } /release") ;
88
+
89
+ workflow . On
90
+ . WorkflowDispatch ( )
91
+ . Inputs ( new StringInput ( "version" , "Version in format X.Y.Z or X.Y.Z-preview." , true , "0.0.0" ) ) ;
92
+
93
+ workflow . EnvDefaults ( ) ;
94
+
95
+ var tagJob = workflow . Job ( "tag" )
96
+ . Name ( "Tag and Pack" )
97
+ . RunsOn ( GitHubHostedRunners . UbuntuLatest )
98
+ . Permissions ( contents : Permission . Write , packages : Permission . Write )
40
99
. Defaults ( ) . Run ( "pwsh" , component . Name )
41
100
. Job ;
42
101
43
- job . Step ( ) . ActionsCheckout ( ) ;
102
+ tagJob . Step ( )
103
+ . ActionsCheckout ( ) ;
104
+
105
+ tagJob . StepSetupDotNet ( ) ;
106
+
107
+ tagJob . Step ( )
108
+ . Name ( "Git tag" )
109
+ . Run ( """
110
+ git config --global user.email "github-bot@duendesoftware.com"
111
+ git config --global user.name "Duende Software GitHub Bot"
112
+ git tag -a it-${{ github.event.inputs.version }} -m "Release v${{ github.event.inputs.version }}"
113
+ git push origin it-${{ github.event.inputs.version }}
114
+ """ ) ;
44
115
45
- job . Step ( ) . ActionsSetupDotNet ( "8.0.x" ) ;
116
+ tagJob . StepInstallCACerts ( ) ;
46
117
47
- foreach ( var testProject in component . Tests )
118
+ foreach ( var project in component . Projects )
48
119
{
49
- var path = $ "{ component . Name } /test/{ testProject } ";
120
+ tagJob . StepPack ( component . Name , project ) ;
121
+ }
122
+
123
+ tagJob . StepSign ( ) ;
124
+
125
+ tagJob . StepPush ( "MyGet" , "https://www.myget.org/F/duende_identityserver/api/v2/package" , "MYGET" ) ;
126
+
127
+ tagJob . StepPush ( "GitHub" , "https://nuget.pkg.github.com/DuendeSoftware/index.json" , "GITHUB_TOKEN" )
128
+ . Env ( ( "GITHUB_TOKEN" , "${{ secrets.GITHUB_TOKEN }}" ) ,
129
+ ( "NUGET_AUTH_TOKEN" , "${{ secrets.GITHUB_TOKEN }}" ) ) ;
130
+
131
+ tagJob . StepUploadArtifacts ( component . Name ) ;
132
+
133
+ var fileName = $ "{ component . Name } -release";
134
+ WriteWorkflow ( workflow , fileName ) ;
135
+ }
136
+
137
+
138
+ foreach ( var component in components )
139
+ {
140
+ GenerateCiWorkflow ( component ) ;
141
+ }
142
+
143
+ record Component ( string Name , string [ ] Projects , string [ ] Tests ) ;
144
+
145
+ public static class StepExtensions
146
+ {
147
+ public static void EnvDefaults ( this Workflow workflow )
148
+ => workflow . Env (
149
+ ( "DOTNETT_NOLOGO" , "true" ) ,
150
+ ( "DOTNET_CLI_TELEMETRY_OPTOUT" , "true" ) ) ;
151
+
152
+ public static void StepSetupDotNet ( this Job job )
153
+ => job . Step ( )
154
+ . Name ( "Setup .NET" )
155
+ . ActionsSetupDotNet ( "8.0.x" ) ;
156
+
157
+ public static Step IfRefMain ( this Step step )
158
+ => step . If ( "github.ref == 'refs/heads/main'" ) ;
159
+
160
+ public static void StepTestAndReport ( this Job job , string componentName , string testProject )
161
+ {
162
+ var path = $ "test/{ testProject } ";
50
163
var logFileName = "Tests.trx" ;
51
164
var flags = $ "--logger \" console;verbosity=normal\" " +
52
165
$ "--logger \" trx;LogFileName={ logFileName } \" " +
@@ -61,25 +174,77 @@ void WriteWorkflow(Workflow workflow, string fileName)
61
174
. If ( "success() || failure()" )
62
175
. With (
63
176
( "name" , "Test Report" ) ,
64
- ( "path" , $ "{ path } /TestResults/{ logFileName } ") ,
177
+ ( "path" , $ "{ componentName } / { path } /TestResults/{ logFileName } ") ,
65
178
( "reporter" , "dotnet-trx" ) ,
66
179
( "fail-on-error" , "true" ) ,
67
180
( "fail-on-empty" , "true" ) ) ;
68
181
}
69
182
70
- job . Step ( )
71
- . Name ( "Install Sectigo CodeSiging CA certificates" )
72
- . Run ( """
73
- sudo apt-get update
74
- sudo apt-get install -y ca-certificates
75
- sudo cp build/SectigoPublicCodeSigningRootCrossAAA.crt /usr/local/share/ca-certificates/
76
- sudo update-ca-certificates
77
-
78
- """ ) ;
79
-
80
- var fileName = $ "{ component . Name } -ci-gen";
183
+ public static void StepInstallCACerts ( this Job job )
184
+ => job . Step ( )
185
+ . Name ( "Install Sectigo CodeSiging CA certificates" )
186
+ . IfRefMain ( )
187
+ . Run ( """
188
+ sudo apt-get update
189
+ sudo apt-get install -y ca-certificates
190
+ sudo cp build/SectigoPublicCodeSigningRootCrossAAA.crt /usr/local/share/ca-certificates/
191
+ sudo update-ca-certificates
192
+ """ ) ;
193
+
194
+ public static void StepToolRestore ( this Job job )
195
+ => job . Step ( )
196
+ . Name ( "Tool restore" )
197
+ . IfRefMain ( )
198
+ . Run ( "dotnet tool restore" ) ;
199
+
200
+ public static void StepPack ( this Job job , string componentName , string project )
201
+ {
202
+ var path = $ "{ componentName } /src/{ project } ";
203
+ job . Step ( )
204
+ . Name ( $ "Pack { project } ")
205
+ . IfRefMain ( )
206
+ . Run ( $ "dotnet pack -c Release { path } --no-build -o artifacts") ;
207
+ }
81
208
82
- WriteWorkflow ( workflow , fileName ) ;
83
- }
209
+ public static void StepSign ( this Job job )
210
+ {
211
+ var flags = "--file-digest sha256 " +
212
+ "--timestamp-rfc3161 http://timestamp.digicert.com " +
213
+ "--azure-key-vault-url https://duendecodesigning.vault.azure.net/ " +
214
+ "--azure-key-vault-client-id 18e3de68-2556-4345-8076-a46fad79e474 " +
215
+ "--azure-key-vault-tenant-id ed3089f0-5401-4758-90eb-066124e2d907 " +
216
+ "--azure-key-vault-client-secret ${{ secrets.SignClientSecret }} " +
217
+ "--azure-key-vault-certificate CodeSigning" ;
218
+ job . Step ( )
219
+ . Name ( "Sign packages" )
220
+ . IfRefMain ( )
221
+ . Run ( $ """
222
+ for file in artifacts/*.nupkg; do
223
+ dotnet NuGetKeyVaultSignTool sign \"$file\" { flags }
224
+ done
225
+ """ ) ;
226
+ }
84
227
85
- record Component ( string Name , string [ ] Projects , string [ ] Tests ) ;
228
+ public static Step StepPush ( this Job job , string destination , string sourceUrl , string secretName )
229
+ {
230
+ var apiKey = $ "${{ secrets.{ secretName } }}";
231
+ return job . Step ( )
232
+ . Name ( $ "Push packages to { destination } ")
233
+ . IfRefMain ( )
234
+ . Run ( $ "dotnet nuget push artifacts/*.nupkg --source { sourceUrl } --api-key { apiKey } --skip-duplicate") ;
235
+ }
236
+
237
+ public static void StepUploadArtifacts ( this Job job , string componentName )
238
+ {
239
+ var path = $ "{ componentName } /artifacts/*.nupkg";
240
+ job . Step ( )
241
+ . Name ( "Upload Artifacts" )
242
+ . IfRefMain ( )
243
+ . Uses ( "actions/upload-artifact@v4" )
244
+ . With (
245
+ ( "name" , "Upload Artifacts" ) ,
246
+ ( "path" , path ) ,
247
+ ( "overwrite" , "true" ) ,
248
+ ( "retention-days" , "15" ) ) ;
249
+ }
250
+ }
0 commit comments