Skip to content

Commit 5a29215

Browse files
committed
Generate CI workflows
1 parent 702c466 commit 5a29215

File tree

6 files changed

+410
-259
lines changed

6 files changed

+410
-259
lines changed

.github/workflow-gen/Program.cs

Lines changed: 201 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
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+
];
321

422
void WriteWorkflow(Workflow workflow, string fileName)
523
{
@@ -8,45 +26,140 @@ void WriteWorkflow(Workflow workflow, string fileName)
826
Console.WriteLine($"Wrote workflow to {filePath}");
927
}
1028

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)
2030
{
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}/**" };
2333

24-
workflow.On.WorkflowDispatch();
34+
workflow.On
35+
.WorkflowDispatch();
2536
workflow.On
2637
.Push()
27-
.Branches("main");
38+
.Paths(paths);
2839
workflow.On
2940
.PullRequest()
3041
.Paths(paths);
3142

32-
workflow.Env(
33-
("DOTNETT_NOLOGO", "true"),
34-
("DOTNET_CLI_TELEMETRY_OPTOUT", "true"));
43+
workflow.EnvDefaults();
3544

3645
var job = workflow
3746
.Job("build")
3847
.Name("Build")
3948
.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)
4099
.Defaults().Run("pwsh", component.Name)
41100
.Job;
42101

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+
""");
44115

45-
job.Step().ActionsSetupDotNet("8.0.x");
116+
tagJob.StepInstallCACerts();
46117

47-
foreach(var testProject in component.Tests)
118+
foreach (var project in component.Projects)
48119
{
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}";
50163
var logFileName = "Tests.trx";
51164
var flags = $"--logger \"console;verbosity=normal\" " +
52165
$"--logger \"trx;LogFileName={logFileName}\" " +
@@ -61,25 +174,77 @@ void WriteWorkflow(Workflow workflow, string fileName)
61174
.If("success() || failure()")
62175
.With(
63176
("name", "Test Report"),
64-
("path", $"{path}/TestResults/{logFileName}"),
177+
("path", $"{componentName}/{path}/TestResults/{logFileName}"),
65178
("reporter", "dotnet-trx"),
66179
("fail-on-error", "true"),
67180
("fail-on-empty", "true"));
68181
}
69182

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+
}
81208

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+
}
84227

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+
}

.github/workflow-gen/workflow-gen.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
</PropertyGroup>
1010

1111
<ItemGroup>
12-
<PackageReference Include="Logicality.GitHub.Actions.Workflow" Version="0.4.0" />
13-
<PackageReference Include="Logicality.GitHub.Actions.Workflow.Extensions" Version="0.4.0" />
12+
<PackageReference Include="Logicality.GitHub.Actions.Workflow" Version="0.5.0" />
13+
<PackageReference Include="Logicality.GitHub.Actions.Workflow.Extensions" Version="0.5.0" />
1414
</ItemGroup>
1515

1616
</Project>

0 commit comments

Comments
 (0)