Oksana Horlock
Posted on September 1, 2021
I'm so happy to get into writing again - we’ve had a few challenging months: we had to self-isolate several times, the whole family was ill with a stomach bug, and our son is going through the terrible twos. So blogging, talks and working on professional development had to be put on the backburner.
I finally had some time to finish writing this blog post about CDK Pipelines I had been working on probably since the beginning of the year. I had been trying to figure out how to make CodeBuild test reports work with CDK Pipelines. Last week when I got back to this and started working on it again, I saw that the API that was used in Developer Preview has been updated (more information on it here). And now it looks like it is easier to plug in the reports to be used with this high level construct. While the old API is still in use, I will focus on the new API.
The purpose of this blog post is to demonstrate the set-up of CodeBuild test reports in CDK Pipelines for C#.
I have written a simple .NET Core application which returns the day of the week when you pass in a date in the query string. There are also a couple of XUnit tests:
public class UnitTests
{
[Fact]
public void DateInPast_ReturnsCorrectResult()
{
var controller = new HomeController();
var date = new DateTime(1983, 2, 3);
var expected = $"{String.Format("{0:d}", date)} was Thursday";
var actual = controller.Get(date) as OkObjectResult;
Assert.Equal(expected, actual.Value);
}
[Fact]
public void DateInFuture_ReturnsCorrectResult()
{
var controller = new HomeController();
var date = new DateTime(2033, 12, 9);
var expected = $"{String.Format("{0:d}", date)} will be Friday";
var actual = controller.Get(date) as OkObjectResult;
Assert.Equal(expected, actual.Value);
}
}
The file tree looks like this:
For the task of creating CodeBuild test reports only without actually deploying the app, we will only work with CdkPipelinesPipelineStack.cs. In my case this was the file created automatically on cdk init
, and it will contain the main pipeline.
Firstly, before we build the pipeline, we need to create a connection to our Github repo and get its ARN. I wrote a post about it a while back – AWS CDK Adventure Part 2: CDK Pipelines and GitHub fun
namespace CdkPipelines
{
public class CdkPipelinesPipelineStack : Stack
{
internal CdkPipelinesPipelineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
{
var connectionArn = "arn:aws:codestar-connections:eu-west-1:01234567890:connection/12ae43b8-923e-4a01-ba4e-274454669859";
}
}
}
We then create a report group:
var reportGroup = new ReportGroup(this, "MyReports", new ReportGroupProps
{
ReportGroupName = "MyReports"
});
After that, we use the CodePipeline construct in the Amazon.CDK.Pipelines namespace to create the pipeline. If we didn’t want to have any CodeBuild reports, we would set up the pipeline like so:
var pipeline = new Amazon.CDK.Pipelines.CodePipeline(this, "WhatDayOfWeekPipeline", new CodePipelineProps
{
PipelineName = "WhatDayOfWeekPipeline",
SelfMutation = false,
Synth = new ShellStep("synth", new ShellStepProps()
{
Input = CodePipelineSource.Connection("OksanaH/CDKPipelines", "main", new ConnectionSourceOptions()
{
ConnectionArn = connectionArn
}),
InstallCommands = new string[] { "npm install -g aws-cdk" },
Commands = new string[] {
"cd App", "dotnet restore WhatDayOfWeekTests/WhatDayOfWeekTests.csproj",
"dotnet test -c release WhatDayOfWeekTests/WhatDayOfWeekTests.csproj --logger trx --results-directory ./testresults",
"cd ..",
"cdk synth" }
})
});
One of the CodePipelineProps is SelfMutation: when set to false, it’s quite handy when doing development work – you can just run cdk deploy
and your local changes to the pipeline will be deployed bypassing the GitHub repo.
Synth property is used to set up the pipeline to pull from the GitHub repo, and also run the commands needed to produce the cloud assembly.
In order to set up the reports, we need to customize the CodeBuild project, and it can be done by using CodeBuildStep class instead of ShellStep. CodeBuildStepProps class, in turn, has a PartialBuildSpec property, which we can use to define the reports. The reports part of a buildspec.yml file usually looks like this:
version: 0.2
phases:
...
reports:
XUnitTestResults:
file-format: VisualStudioTrx
files:
- '**/*'
base-directory: './testresults'
In CDK for C# the value of PartialBuildSpec has to be created using Dictionary, and the reports bit translated to CDK is below:
var reports = new Dictionary<string, object>()
{
{
"reports", new Dictionary<string, object>()
{
{
reportGroup.ReportGroupArn, new Dictionary<string,object>()
{
{ "file-format", "VisualStudioTrx" },
{ "files", "**/*" },
{ "base-directory", "App/testresults" }
}
}
}
}
};
Another thing that needs to be created to be able to work with CodeBuild test reports is a policy, otherwise you might see an error like this when you try to deploy the stack:
The policy allows several report-related actions on the report group we have created:
var policyProps = new PolicyStatementProps()
{
Actions = new string[] {
"codebuild:CreateReportGroup",
"codebuild:CreateReport",
"codebuild:UpdateReport",
"codebuild:BatchPutTestCases",
"codebuild:BatchPutCodeCoverages"
},
Effect = Effect.ALLOW,
Resources = new string[] { reportGroup.ReportGroupArn }
};
Next, we can define necessary CodeBuildStepProps to set up reports:
var step = new CodeBuildStep("Synth", new CodeBuildStepProps
{
Input = CodePipelineSource.Connection("OksanaH/CDKPipelines", "main", new ConnectionSourceOptions()
{
ConnectionArn = connectionArn
}),
PrimaryOutputDirectory = "cdk.out",
InstallCommands = new string[] { "npm install -g aws-cdk" },
Commands = new string[] {
"cd App",
"dotnet restore WhatDayOfWeekTests/WhatDayOfWeekTests.csproj",
"dotnet test -c release WhatDayOfWeekTests/WhatDayOfWeekTests.csproj --logger trx --results-directory ./testresults",
"cd ..",
"cdk synth"
},
PartialBuildSpec = BuildSpec.FromObject(reports),
RolePolicyStatements = new PolicyStatement[] { new PolicyStatement(policyProps) }
});
Now, what is left to do is to use the CodeBuildStep as the value of the Synth property:
var pipeline = new Amazon.CDK.Pipelines.CodePipeline(this, "WhatDayOfWeekPipeline", new CodePipelineProps
{
PipelineName = "WhatDayOfWeekPipeline",
Synth = step
}
After that we can commit the changes, run cdk deploy
and check the CodeBuild test report in the console:
Beautiful!
Useful links:
Posted on September 1, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.