Skip to content

Commit 3833678

Browse files
committed
Added Build project and github actions file for the build
1 parent 22ae4d0 commit 3833678

File tree

7 files changed

+342
-0
lines changed

7 files changed

+342
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Build and Deploy
2+
3+
on:
4+
push:
5+
branches: [main]
6+
workflow_dispatch:
7+
workflow_call:
8+
9+
jobs:
10+
build-and-publish:
11+
runs-on: ubuntu-latest
12+
env:
13+
CONFIGURATION: Release
14+
DOTNET_VERSION: 8.0.x
15+
SITE_PROJECT_NAME: SvgHelpers
16+
SRC_DIRECTORY_PATH: ${{ github.workspace }}/src/
17+
BUILD_ARTIFACTS_PATH: ${{ github.workspace }}/build_artifacts
18+
PULUMI_PROJECT_DIRECTORY: ${{ github.workspace }}/infra/pulumi-infra-deploy
19+
PULUMI_PROJECT_FILE_PATH: ${{ github.workspace }}/infra/pulumi-infra-deploy/pulumi-infra-deploy.csproj
20+
DYNAMIC_CONTENT_UPDATER_OUTPUT_PATH: ${{ github.workspace }}/static_content_output
21+
PULUMI_STACK_NAME: prod
22+
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
23+
24+
steps:
25+
- uses: actions/checkout@v2
26+
- name: Setup .NET
27+
uses: actions/setup-dotnet@v1
28+
with:
29+
dotnet-version: ${{ env.DOTNET_VERSION }}
30+
- name: Setup Node
31+
uses: actions/setup-node@v3
32+
with:
33+
node-version: 18.3.0
34+
- name: Install Cloudflare Wrangler
35+
run: npm install --location=global wrangler
36+
- name: Install Pulumi
37+
uses: pulumi/setup-pulumi@v2
38+
39+
- name: Dotnet Restore - Pulumi Project
40+
run: dotnet restore ${{ env.PULUMI_PROJECT_FILE_PATH }}
41+
42+
- name: Cake - Build
43+
run: dotnet run --project build/build/Build.csproj -- --configuration=${{ env.CONFIGURATION }} --srcDirectoryPath=${{ env.SRC_DIRECTORY_PATH }} --BuildArtifactsPath=${{ env.BUILD_ARTIFACTS_PATH }}
44+
45+
# - name: Cake - Deploy
46+
# run: dotnet run --project ${{ github.workspace }}/deploy/deploy/Deploy.csproj -- --configuration=${{ env.CONFIGURATION }} --PulumiStackName=${{ env.PULUMI_STACK_NAME }} --WorkspacePath=${{ github.workspace }} --BuildArtifactsPath=${{ env.BUILD_ARTIFACTS_PATH }}
47+
48+

build/build.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
dotnet run --project build/Build.csproj -- $args
2+
exit $LASTEXITCODE;

build/build.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dotnet run --project ./build/Build.csproj -- "$@"
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using Cake.Common;
2+
using Cake.Core;
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Collections.Immutable;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
11+
public record WebsitePaths(
12+
string ProjectName,
13+
string PathToSln,
14+
string ProjectFolder,
15+
string CsprojFile,
16+
string OutDir,
17+
string ZipOutDir,
18+
string ZipOutFilePath,
19+
string UnitTestDirectory,
20+
string UnitTestProj,
21+
string CoverletOutDir,
22+
string CustomJsModulesDir)
23+
{
24+
public static WebsitePaths LoadFromContext(ICakeContext context, string buildConfiguration, string srcDirectory, string buildArtifactsPath)
25+
{
26+
var projectName = "SvgHelpers";
27+
srcDirectory += $"/{projectName}";
28+
var pathToSln = srcDirectory + $"/{projectName}.sln";
29+
var functionProjectDir = srcDirectory + $"/{projectName}";
30+
var functionCsprojFile = functionProjectDir + $"/{projectName}.csproj";
31+
var outDir = functionProjectDir + $"/bin/{buildConfiguration}/cake-build-output";
32+
var zipOutDir = buildArtifactsPath;
33+
var zipOutFilePath = zipOutDir + $"/svg-helpers-site.zip";
34+
var unitTestDirectory = srcDirectory + $"/UnitTests";
35+
var unitTestProj = unitTestDirectory + $"/UnitTests.csproj";
36+
var coverletOutDir = unitTestDirectory + $"/coverlet-coverage-results/";
37+
var customJsModulesDir = srcDirectory + $"/CustomNpmModules/";
38+
39+
return new WebsitePaths(
40+
projectName,
41+
pathToSln,
42+
functionProjectDir,
43+
functionCsprojFile,
44+
outDir,
45+
zipOutDir,
46+
zipOutFilePath,
47+
unitTestDirectory,
48+
unitTestProj,
49+
coverletOutDir,
50+
customJsModulesDir);
51+
}
52+
}

build/build/Build.csproj

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
7+
<LangVersion>preview</LangVersion>
8+
<RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>
9+
</PropertyGroup>
10+
<ItemGroup>
11+
<PackageReference Include="Cake.Frosting" Version="4.0.0" />
12+
<PackageReference Include="Cake.GitHub" Version="0.1.0" />
13+
<PackageReference Include="Cake.Npm" Version="4.0.0" />
14+
</ItemGroup>
15+
</Project>

build/build/Build.sln

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.31912.275
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Build", "Build.csproj", "{0C92FB17-0701-445C-8DA8-4065442B48C5}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{0C92FB17-0701-445C-8DA8-4065442B48C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{0C92FB17-0701-445C-8DA8-4065442B48C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{0C92FB17-0701-445C-8DA8-4065442B48C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{0C92FB17-0701-445C-8DA8-4065442B48C5}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {4B8CCF56-5733-4E25-A930-E35CF2132F0F}
24+
EndGlobalSection
25+
EndGlobal

build/build/Program.cs

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Cake.Core;
4+
using Cake.Core.Diagnostics;
5+
using Cake.Frosting;
6+
using Cake.Common;
7+
using Cake.Common.IO;
8+
using System.IO;
9+
using System.IO.Compression;
10+
using Cake.Common.Tools.DotNet;
11+
using Cake.Common.Tools.DotNet.Restore;
12+
using Cake.Npm;
13+
using Cake.Npm.RunScript;
14+
using System.Threading;
15+
using System.Linq;
16+
using Cake.Common.Tools.DotNet.Build;
17+
using Cake.Common.Tools.DotNet.Test;
18+
using Cake.Common.Tools.DotNet.Publish;
19+
using NuGet.Packaging;
20+
using System.Collections.Generic;
21+
22+
public static class Program
23+
{
24+
public static int Main(string[] args)
25+
{
26+
return new CakeHost()
27+
.UseContext<BuildContext>()
28+
.Run(args);
29+
}
30+
}
31+
32+
public class BuildContext : FrostingContext
33+
{
34+
public string Target { get; }
35+
public string BuildConfiguration { get; }
36+
public string SrcDirectoryPath { get; }
37+
public string BuildArtifactsPath { get; }
38+
public WebsitePaths WebClientPaths { get; }
39+
40+
public BuildContext(ICakeContext context)
41+
: base(context)
42+
{
43+
Target = context.Argument("target", "Default");
44+
BuildConfiguration = context.Argument<string>("configuration");
45+
SrcDirectoryPath = context.Argument<string>("srcDirectoryPath");
46+
BuildArtifactsPath = context.Argument<string>("BuildArtifactsPath");
47+
48+
WebClientPaths = WebsitePaths.LoadFromContext(context, BuildConfiguration, SrcDirectoryPath, BuildArtifactsPath);
49+
}
50+
}
51+
52+
[TaskName(nameof(OutputParametersTask))]
53+
public sealed class OutputParametersTask : FrostingTask<BuildContext>
54+
{
55+
public override void Run(BuildContext context)
56+
{
57+
context.Log.Information($"INFO: Current Working Directory: {context.Environment.WorkingDirectory}");
58+
59+
context.Log.Information($"INFO: {nameof(context.BuildConfiguration)}: {context.BuildConfiguration}");
60+
context.Log.Information($"INFO: {nameof(context.SrcDirectoryPath)}: {context.SrcDirectoryPath}");
61+
}
62+
}
63+
64+
[IsDependentOn(typeof(OutputParametersTask))]
65+
[TaskName(nameof(CleanTask))]
66+
public sealed class CleanTask : FrostingTask<BuildContext>
67+
{
68+
public override void Run(BuildContext context)
69+
{
70+
context.CleanDirectory(context.WebClientPaths.OutDir);
71+
}
72+
}
73+
74+
[IsDependentOn(typeof(CleanTask))]
75+
[TaskName(nameof(BuildTask))]
76+
public sealed class BuildTask : FrostingTask<BuildContext>
77+
{
78+
public override void Run(BuildContext context)
79+
{
80+
//Tasks to build custom NPM packages for public web app
81+
var buildCustomJsModulesWebAppFuncs = Directory
82+
.EnumerateDirectories(context.WebClientPaths.CustomJsModulesDir, "*", SearchOption.TopDirectoryOnly)
83+
.Select(x => new Action(() => PublishCustomJsModule(context, x)));
84+
85+
//.NET Build tasks
86+
var buildDotnetAppFuncs = new[]
87+
{
88+
() => BuildDotnetApp(context, context.WebClientPaths.PathToSln),
89+
};
90+
91+
var buildFuncs = buildDotnetAppFuncs.Concat(buildCustomJsModulesWebAppFuncs).ToArray();
92+
93+
var runner = Parallel.ForEach(buildFuncs, func => func());
94+
while (!runner.IsCompleted)
95+
{
96+
Thread.Sleep(100);
97+
}
98+
}
99+
100+
private void BuildDotnetApp(BuildContext context, string pathToSln)
101+
{
102+
context.DotNetRestore(pathToSln);
103+
104+
context.DotNetBuild(pathToSln, new DotNetBuildSettings
105+
{
106+
NoRestore = true,
107+
Configuration = context.BuildConfiguration
108+
});
109+
}
110+
111+
private void PublishCustomJsModule(BuildContext context, string workingDirectory)
112+
{
113+
var settings = new NpmRunScriptSettings
114+
{
115+
WorkingDirectory = workingDirectory,
116+
ScriptName = "publish"
117+
};
118+
119+
NpmRunScriptAliases.NpmRunScript(context, settings);
120+
}
121+
}
122+
123+
[IsDependentOn(typeof(BuildTask))]
124+
[TaskName(nameof(RunUnitTestsTask))]
125+
public sealed class RunUnitTestsTask : FrostingTask<BuildContext>
126+
{
127+
public override void Run(BuildContext context)
128+
{
129+
var testSettings = new DotNetTestSettings()
130+
{
131+
Configuration = context.BuildConfiguration,
132+
NoBuild = true,
133+
ArgumentCustomization = (args) => args.Append("/p:CollectCoverage=true /p:CoverletOutputFormat=cobertura --logger trx")
134+
};
135+
136+
var runTestsFuncs = new[]
137+
{
138+
() => context.DotNetTest(context.WebClientPaths.UnitTestProj, testSettings),
139+
};
140+
141+
var runner = Parallel.ForEach(runTestsFuncs, func => func());
142+
while (!runner.IsCompleted)
143+
{
144+
Thread.Sleep(100);
145+
}
146+
}
147+
}
148+
149+
[IsDependentOn(typeof(RunUnitTestsTask))]
150+
[TaskName(nameof(PublishApplicationsTask))]
151+
public sealed class PublishApplicationsTask : FrostingTask<BuildContext>
152+
{
153+
public override void Run(BuildContext context)
154+
{
155+
var buildFuncs = new List<Action>
156+
{
157+
() => PublishWebClient(context),
158+
};
159+
160+
var runner = Parallel.ForEach(buildFuncs, func => func());
161+
while (!runner.IsCompleted)
162+
{
163+
Thread.Sleep(100);
164+
}
165+
}
166+
167+
private void PublishWebClient(BuildContext context)
168+
{
169+
var settings = new DotNetPublishSettings()
170+
{
171+
NoRestore = true,
172+
NoBuild = true,
173+
Configuration = context.BuildConfiguration,
174+
OutputDirectory = context.WebClientPaths.OutDir,
175+
};
176+
177+
context.DotNetPublish(context.WebClientPaths.CsprojFile, settings);
178+
179+
//Now that the code is published, create the compressed folder
180+
if (!Directory.Exists(context.WebClientPaths.ZipOutDir))
181+
{
182+
_ = Directory.CreateDirectory(context.WebClientPaths.ZipOutDir);
183+
}
184+
185+
if (File.Exists(context.WebClientPaths.ZipOutFilePath))
186+
{
187+
File.Delete(context.WebClientPaths.ZipOutFilePath);
188+
}
189+
190+
ZipFile.CreateFromDirectory(context.WebClientPaths.OutDir, context.WebClientPaths.ZipOutFilePath);
191+
context.Log.Information($"Output client web app zip file to: {context.WebClientPaths.ZipOutFilePath}");
192+
}
193+
}
194+
195+
[IsDependentOn(typeof(PublishApplicationsTask))]
196+
[TaskName("Default")]
197+
public class DefaultTask : FrostingTask
198+
{
199+
}

0 commit comments

Comments
 (0)