Skip to content

Commit b8d8945

Browse files
committed
Generate CI workflows
1 parent 702c466 commit b8d8945

10 files changed

+668
-423
lines changed

.github/workflow-gen/Program.cs

Lines changed: 223 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,185 @@
11
using Logicality.GitHub.Actions.Workflow;
2-
using System.IO;
32

4-
void WriteWorkflow(Workflow workflow, string fileName)
5-
{
6-
var filePath = $"../workflows/{fileName}.yml";
7-
workflow.WriteYaml(filePath);
8-
Console.WriteLine($"Wrote workflow to {filePath}");
9-
}
3+
Component[] components = [
4+
new("ignore-this",
5+
["IgnoreThis"],
6+
["IgnoreThis.Tests"]),
107

8+
new("access-token-management",
9+
["AccessTokenManagement", "AccessTokenManagement.OpenIdConnect"],
10+
["AccessTokenManagement.Tests"]),
1111

12-
Component[] components = [
13-
new("ignore-this", ["IgnoreThis"], ["IgnoreThis.Tests"]),
14-
];
15-
16-
(string Key, string Value) EnvSecret(string key) => (key, $"${{secrets.{key}}}");
12+
new("identity-model",
13+
["IdentityModel"],
14+
["IdentityModel.Tests"]),
1715

16+
new("identity-model-oidc-client",
17+
["IdentityModel.OidcClient", "IdentityModel.OidcClient.DPoP", "IdentityModel.OidcClient.IdentityTokenValidator"],
18+
["IdentityModel.OidcClient.Tests", "IdentityModel.OidcClient.DPoP.Tests", "IdentityModel.OidcClient.IdentityTokenValidator.Tests"])
19+
];
1820

1921
foreach (var component in components)
2022
{
21-
var workflow = new Workflow($"{component.Name}-ci");
22-
var paths = new[] { $".github/workflows/{component.Name}-ci", $"src/{component.Name}/**" };
23+
GenerateCiWorkflow(component);
24+
GenerateReleaseWorkflow(component);
25+
}
26+
27+
void GenerateCiWorkflow(Component component)
28+
{
29+
var workflow = new Workflow($"{component.Name}/ci");
30+
var paths = new[] { $".github/workflows/{component.Name}-**", $"src/{component.Name}/**" };
2331

24-
workflow.On.WorkflowDispatch();
32+
workflow.On
33+
.WorkflowDispatch();
2534
workflow.On
2635
.Push()
27-
.Branches("main");
36+
.Paths(paths);
2837
workflow.On
2938
.PullRequest()
3039
.Paths(paths);
3140

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

3643
var job = workflow
3744
.Job("build")
3845
.Name("Build")
3946
.RunsOn(GitHubHostedRunners.UbuntuLatest)
47+
.Defaults().Run("bash", component.Name)
48+
.Job;
49+
50+
job.Step()
51+
.ActionsCheckout();
52+
53+
job.StepSetupDotNet();
54+
55+
foreach (var testProject in component.Tests)
56+
{
57+
job.StepTestAndReport(component.Name, testProject);
58+
}
59+
60+
job.StepInstallCACerts();
61+
62+
job.StepToolRestore();
63+
64+
foreach (var project in component.Projects)
65+
{
66+
job.StepPack(component.Name, project);
67+
}
68+
69+
job.StepSign();
70+
71+
job.StepPush("MyGet", "https://www.myget.org/F/duende_identityserver/api/v2/package", "MYGET");
72+
73+
job.StepPush("GitHub", "https://nuget.pkg.github.com/DuendeSoftware/index.json", "GITHUB_TOKEN")
74+
.Env(("GITHUB_TOKEN", "${{ secrets.GITHUB_TOKEN }}"),
75+
("NUGET_AUTH_TOKEN", "${{ secrets.GITHUB_TOKEN }}"));
76+
77+
job.StepUploadArtifacts(component.Name);
78+
79+
var fileName = $"{component.Name}-ci";
80+
WriteWorkflow(workflow, fileName);
81+
}
82+
83+
void GenerateReleaseWorkflow(Component component)
84+
{
85+
var workflow = new Workflow($"{component.Name}/release");
86+
87+
workflow.On
88+
.WorkflowDispatch()
89+
.Inputs(new StringInput("version", "Version in format X.Y.Z or X.Y.Z-preview.", true, "0.0.0"));
90+
91+
workflow.EnvDefaults();
92+
93+
var tagJob = workflow.Job("tag")
94+
.Name("Tag and Pack")
95+
.RunsOn(GitHubHostedRunners.UbuntuLatest)
96+
.Permissions(contents: Permission.Write, packages: Permission.Write)
4097
.Defaults().Run("pwsh", component.Name)
4198
.Job;
4299

43-
job.Step().ActionsCheckout();
100+
tagJob.Step()
101+
.ActionsCheckout();
102+
103+
tagJob.StepSetupDotNet();
104+
105+
tagJob.Step()
106+
.Name("Git tag")
107+
.Run("""
108+
git config --global user.email "github-bot@duendesoftware.com"
109+
git config --global user.name "Duende Software GitHub Bot"
110+
git tag -a it-${{ github.event.inputs.version }} -m "Release v${{ github.event.inputs.version }}"
111+
git push origin it-${{ github.event.inputs.version }}
112+
""");
113+
114+
tagJob.StepInstallCACerts();
115+
116+
foreach (var project in component.Projects)
117+
{
118+
tagJob.StepPack(component.Name, project);
119+
}
120+
121+
tagJob.StepSign();
44122

45-
job.Step().ActionsSetupDotNet("8.0.x");
123+
tagJob.StepPush("MyGet", "https://www.myget.org/F/duende_identityserver/api/v2/package", "MYGET");
46124

47-
foreach(var testProject in component.Tests)
125+
tagJob.StepPush("GitHub", "https://nuget.pkg.github.com/DuendeSoftware/index.json", "GITHUB_TOKEN")
126+
.Env(("GITHUB_TOKEN", "${{ secrets.GITHUB_TOKEN }}"),
127+
("NUGET_AUTH_TOKEN", "${{ secrets.GITHUB_TOKEN }}"));
128+
129+
tagJob.StepUploadArtifacts(component.Name);
130+
131+
var publishJob = workflow.Job("publish")
132+
.Name("Publish to nuget.org")
133+
.RunsOn(GitHubHostedRunners.UbuntuLatest)
134+
.Environment("nuget.org", "");
135+
136+
publishJob.Step()
137+
.Uses("actions/download-artifact@v4")
138+
.With(("name", "artifacts"), ("path", "artifacts"));
139+
140+
publishJob.StepSetupDotNet();
141+
142+
publishJob.Step()
143+
.Name("List files")
144+
.Shell("bash")
145+
.Run("tree");
146+
147+
publishJob.StepPush("nuget.org", "https://api.nuget.org/v3/index.json", "NUGET_ORG_API_KEY");
148+
149+
var fileName = $"{component.Name}-release";
150+
WriteWorkflow(workflow, fileName);
151+
}
152+
153+
void WriteWorkflow(Workflow workflow, string fileName)
154+
{
155+
var filePath = $"../workflows/{fileName}.yml";
156+
workflow.WriteYaml(filePath);
157+
Console.WriteLine($"Wrote workflow to {filePath}");
158+
}
159+
160+
161+
162+
163+
record Component(string Name, string[] Projects, string[] Tests);
164+
165+
public static class StepExtensions
166+
{
167+
public static void EnvDefaults(this Workflow workflow)
168+
=> workflow.Env(
169+
("DOTNETT_NOLOGO", "true"),
170+
("DOTNET_CLI_TELEMETRY_OPTOUT", "true"));
171+
172+
public static void StepSetupDotNet(this Job job)
173+
=> job.Step()
174+
.Name("Setup .NET")
175+
.ActionsSetupDotNet("8.0.x");
176+
177+
public static Step IfRefMain(this Step step)
178+
=> step.If("github.ref == 'refs/heads/main'");
179+
180+
public static void StepTestAndReport(this Job job, string componentName, string testProject)
48181
{
49-
var path = $"{component.Name}/test/{testProject}";
182+
var path = $"test/{testProject}";
50183
var logFileName = "Tests.trx";
51184
var flags = $"--logger \"console;verbosity=normal\" " +
52185
$"--logger \"trx;LogFileName={logFileName}\" " +
@@ -61,25 +194,77 @@ void WriteWorkflow(Workflow workflow, string fileName)
61194
.If("success() || failure()")
62195
.With(
63196
("name", "Test Report"),
64-
("path", $"{path}/TestResults/{logFileName}"),
197+
("path", $"{componentName}/{path}/TestResults/{logFileName}"),
65198
("reporter", "dotnet-trx"),
66199
("fail-on-error", "true"),
67200
("fail-on-empty", "true"));
68201
}
69202

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";
203+
public static void StepInstallCACerts(this Job job)
204+
=> job.Step()
205+
.Name("Install Sectigo CodeSiging CA certificates")
206+
.IfRefMain()
207+
.Run("""
208+
sudo apt-get update
209+
sudo apt-get install -y ca-certificates
210+
sudo cp build/SectigoPublicCodeSigningRootCrossAAA.crt /usr/local/share/ca-certificates/
211+
sudo update-ca-certificates
212+
""");
81213

82-
WriteWorkflow(workflow, fileName);
83-
}
214+
public static void StepToolRestore(this Job job)
215+
=> job.Step()
216+
.Name("Tool restore")
217+
.IfRefMain()
218+
.Run("dotnet tool restore");
84219

85-
record Component(string Name, string[] Projects, string[] Tests);
220+
public static void StepPack(this Job job, string componentName, string project)
221+
{
222+
var path = $"{componentName}/src/{project}";
223+
job.Step()
224+
.Name($"Pack {project}")
225+
.IfRefMain()
226+
.Run($"dotnet pack -c Release {path} --no-build -o artifacts");
227+
}
228+
229+
public static void StepSign(this Job job)
230+
{
231+
var flags = "--file-digest sha256 " +
232+
"--timestamp-rfc3161 http://timestamp.digicert.com " +
233+
"--azure-key-vault-url https://duendecodesigning.vault.azure.net/ " +
234+
"--azure-key-vault-client-id 18e3de68-2556-4345-8076-a46fad79e474 " +
235+
"--azure-key-vault-tenant-id ed3089f0-5401-4758-90eb-066124e2d907 " +
236+
"--azure-key-vault-client-secret ${{ secrets.SignClientSecret }} " +
237+
"--azure-key-vault-certificate CodeSigning";
238+
job.Step()
239+
.Name("Sign packages")
240+
.IfRefMain()
241+
.Run($"""
242+
for file in artifacts/*.nupkg; do
243+
dotnet NuGetKeyVaultSignTool sign \"$file\" {flags}
244+
done
245+
""");
246+
}
247+
248+
public static Step StepPush(this Job job, string destination, string sourceUrl, string secretName)
249+
{
250+
var apiKey = $"${{ secrets.{secretName} }}";
251+
return job.Step()
252+
.Name($"Push packages to {destination}")
253+
.IfRefMain()
254+
.Run($"dotnet nuget push artifacts/*.nupkg --source {sourceUrl} --api-key {apiKey} --skip-duplicate");
255+
}
256+
257+
public static void StepUploadArtifacts(this Job job, string componentName)
258+
{
259+
var path = $"{componentName}/artifacts/*.nupkg";
260+
job.Step()
261+
.Name("Upload Artifacts")
262+
.IfRefMain()
263+
.Uses("actions/upload-artifact@v4")
264+
.With(
265+
("name", "artifacts"),
266+
("path", path),
267+
("overwrite", "true"),
268+
("retention-days", "15"));
269+
}
270+
}

.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)