A Piece of Cake: C# powered cross platform build automation
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 96 | |
Author | ||
License | CC Attribution - NonCommercial - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/51694 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
NDC Oslo 20161 / 96
2
7
8
9
12
14
19
20
26
28
31
33
38
40
43
45
48
50
51
61
63
65
76
79
80
83
87
88
90
93
94
96
00:00
EmailTwitterComputing platformPhysical systemCodeDressing (medical)Execution unitComputer fileBuildingSoftware testingUtility softwareProjective planeStandard deviationMathematical analysisStack (abstract data type)QuicksortSoftware developerProcess (computing)Integrated development environmentResultantCodeComputing platformPoint (geometry)Core dumpMereology.NET FrameworkDemo (music)Computer fileData miningoutputAutomationTask (computing)Graph (mathematics)Software development kitProduct (business)WebsiteBuildingSoftware testingLine (geometry)BitIdentity managementScripting languageCompilerWhiteboardFunction (mathematics)Execution unitVariable (mathematics)Repository (publishing)Visualization (computer graphics)Parameter (computer programming)Term (mathematics)NumberConfiguration spaceAdditionOrder (biology)Data storage deviceData structureIdeal (ethics)Unit testingWeightOpen sourcePlug-in (computing)Computer animation
06:55
Configuration spacePlug-in (computing)Software testingExplosionSinguläres IntegralCovering spaceCodeOpen setDataflowLink (knot theory)BuildingGastropod shellPower (physics)Execution unitRevision controlSoftware testingPhysical systemRevision controlComputer fileFunction (mathematics)Stress (mechanics)Error messageCore dumpCode1 (number)Source codeRepository (publishing)Plug-in (computing)Projective planeSelf-organizationPoint (geometry)MereologyPointer (computer programming)Extension (kinesiology)Product (business)Existential quantificationData managementNumberC sharpMessage passingIntegrated development environmentVisualization (computer graphics)Virtual machineTelecommunicationParameter (computer programming)BuildingOpen sourcePreprocessorDirection (geometry)Installation artCategory of beingNormal (geometry)NeuroinformatikUnit testingComputer configurationProcess (computing)Scripting languageWeightReal numberCompilerInstance (computer science)AdditionWater vaporForm (programming)Compilation albumView (database)Shift operatorGame controllerDataflowComputer animation
13:46
Binary fileRepository (publishing)Integrated development environmentPhysical systemServer (computing)System programmingSoftware testingSource codeHoaxMereologyDemo (music)1 (number)Data conversionGoodness of fitExtension (kinesiology)Fitness functionUnit testingContinuous integrationBinary codeProcess (computing)Physical systemPower (physics)Computer fileData managementAliasingMultiplication signPrice indexCore dumpOrder (biology)Projective planeFormal languageSoftware developerSoftware testingIntegrated development environmentSoftware repositoryNumberDifferent (Kate Ryan album)Latent heatImplementationBuildingFinite differenceRevision controlForcing (mathematics)Server (computing)ResultantService (economics)Message passingLogicPolygonInstance (computer science)Software development kitCodeExecution unitProduct (business)Field (computer science)Computer animation
20:37
Connected spaceOrder (biology)Local ringRepository (publishing)Computer configurationConfiguration spaceDemo (music)Asynchronous Transfer ModeInternetworkingTerm (mathematics)Instance (computer science)Computer animation
21:27
Sample (statistics)Computer fileGame controllerExecution unitInstallation artConfiguration spaceSource codeParameter (computer programming)Task (computing)Scripting languageDemo (music)GodIntegrated development environmentVisualization (computer graphics)Configuration spaceWindowMereologyCodeProjective planeOrder (biology)Sampling (statistics)Equivalence relationLibrary (computing)Graph (mathematics)BuildingTask (computing)Computer fileType theoryNumberLine (geometry)Parameter (computer programming)Point (geometry)Default (computer science)Application service providerCuboidSoftware testingWeb applicationSound effectFunctional (mathematics)Core dumpConnectivity (graph theory)Game controllerPhysical systemExtension (kinesiology)Data storage deviceGreatest elementCASE <Informatik>Computer configurationProcess (computing)Instance (computer science)Image resolutionLevel (video gaming)Revision controlBootstrap aggregatingGraph (mathematics)Computer animationSource code
28:03
Parameter (computer programming)Default (computer science)MereologyCodeMessage passingMultiplication signInteractive televisionRadical (chemistry)Data storage deviceComputer fileComputer animation
28:48
Interior (topology)Default (computer science)Execution unitBitProcess (computing)Function (mathematics)BuildingWindowProjective planeMultiplication signSource codeComputer animation
29:53
Parameter (computer programming)Default (computer science)Source codeoutputSystem callUniform resource locatorVisualization (computer graphics)Point (geometry)Latent heatMereologyTypprüfungSource codeComputer fileProcess (computing)Data storage deviceAliasingParameter (computer programming)QuicksortCASE <Informatik>Computer animation
31:07
Convex hullInsertion lossInclusion mapLocal ringBitScripting languageMereologyVisualization (computer graphics)Task (computing)Application service providerTemplate (C++)Physical systemDefault (computer science)Order (biology)Integrated development environmentProcess (computing)CASE <Informatik>Shift operatorSource codeComputer animation
32:18
Pointer (computer programming)Convex hullSpecial linear groupComputer-generated imagerySample (statistics)Configuration spaceTask (computing)Source codeBinary fileProjective planeScripting languageFunction (mathematics)MereologyConfiguration spaceRevision controlError messageComputer fileParameter (computer programming)Demo (music)Online helpSet (mathematics)BuildingCategory of beingComputer configurationExtension (kinesiology)WindowInformationoutputAdditionVisualization (computer graphics)Uniform resource locatorProcess (computing)Latent heatInstance (computer science)Social classWeb pageSource codeComputer animation
34:35
Maxima and minimaDefault (computer science)Convex hullGamma functionLimit (category theory)Task (computing)MereologyDefault (computer science)Graph (mathematics)BuildingLine (geometry)Binary fileProjective planeData storage deviceComputer animationSource code
35:23
Sample (statistics)Source codeSummierbarkeitBuildingWindowTask (computing).NET FrameworkIntegrated development environmentCore dumpScripting languageApplication service providerTerm (mathematics)Statement (computer science)Computing platform1 (number)Software development kitElement (mathematics)Instance (computer science)AdditionDecision theoryShooting methodWeightReverse engineeringComputer animation
37:03
Configuration spaceFunction (mathematics)Directory serviceTask (computing)Software testingUnit testingExecution unitProjective planeParameter (computer programming)MereologyBuildingSoftware testingTraffic reportingFunction (mathematics)Task (computing)Directory serviceAliasingNumberUniform resource locatorGraph (mathematics)Computer animation
37:48
SummierbarkeitConvex hullAnnulus (mathematics)Parameter (computer programming)Default (computer science)Video game consoleConfiguration spaceSample (statistics)Unit testingExpected valueAliasingVirtual machineVisualization (computer graphics)Installation artExecution unitData storage deviceMereologyImage resolutionAdditionParameter (computer programming)BuildingRevision controlDefault (computer science)Process (computing)PreprocessorDirection (geometry)Different (Kate Ryan album)Repository (publishing)Computer animationSource code
39:19
Convex hullBuildingPhysical systemComputer configurationData bufferBoolean algebraString (computer science)Sample (statistics)Error messageAsynchronous Transfer ModeSalem, IllinoisGeneric programmingComputer programElectronic mailing listSoftware testingConfiguration spaceSource codeSpecial linear groupMultiplication signGoogolVideo game consoleDemo (music)MereologyExecution unitFunction (mathematics)Unit testingDirectory serviceAliasingSoftware testingFile systemResultantOrder (biology)Field (computer science)BuildingProcess (computing)Electronic mailing listTask (computing)Computer fileExistenceSource codeComputer animation
41:01
Convex hullEmailSample (statistics)Game controllerCodierung <Programmierung>Revision controlComputer fileFile formatView (database)Assembly languageIntegrated development environmentWeightBuildingProcess (computing)Software testingFunction (mathematics)Multiplication signMereologyResultantExecution unitSoftware developerCovering spaceVisualization (computer graphics)Projective planeSampling (statistics)Source codeComputer animation
41:49
Revision controlLibrary (computing)Sample (statistics)Computer fileSource codeSoftware testingFunction (mathematics)Directory serviceInclusion mapGraphic designDemonMIDIDefault (computer science)Task (computing)Directory serviceFunction (mathematics)Physical systemComputer fileCategory of beingBuildingAliasingComplete metric spaceoutputMereologySet (mathematics)Demo (music)Type theoryGreatest elementTerm (mathematics)Multiplication signProcess (computing)Projective planeComputer animation
43:45
Session Initiation ProtocolSample (statistics)CubeContent (media)Mathematical singularitySimulationConvex hulloutputParameter (computer programming)Configuration spaceTask (computing)System callExecution unitUnit testingData storage deviceScripting languageRevision controlNumberDebuggerPhysical systemComputer fileVisualization (computer graphics)PreprocessorDirection (geometry)Control flowBuildingPoint (geometry)Continuous integrationFunction (mathematics)Repository (publishing)Demo (music)Slide ruleVirtual machineMultiplication signQuicksortQueue (abstract data type)MereologyServer (computing)BootingSource codeComputer animation
47:29
Sample (statistics)Default (computer science)Configuration spaceDebuggerProcess (computing)Task (computing)EmulationParameter (computer programming)Special linear groupBuildingString (computer science)Computer fileLibrary (computing)Hydraulic jumpMultiplication signComputer fileDirection (geometry)Process (computing)DebuggerBuildingVisualization (computer graphics)PreprocessorScripting languageCategory of beingFunction (mathematics)Physical systemSlide ruleStatement (computer science)Computer configurationControl flowPoint (geometry)FreewareRevision controlStructural loadWindowComputer animationSource code
49:33
Computing platformAutomationComputer wormTelephone number mappingAnalog-to-digital converterConvex hullBlogTwitterEmailCodierung <Programmierung>Continuous integrationLaurent seriesGame controllerDemo (music)Slide ruleBuildingBlogUnit testingComputer configurationOpen sourceProfil (magazine)Shape (magazine)Computer file.NET FrameworkSelf-organizationProjective planeInstance (computer science)Identity managementServer (computing)Core dumpApplication service providerPhysical systemScripting languagePoint (geometry)Form (programming)Process (computing)Computing platformBootstrap aggregatingQueue (abstract data type)Right angleWeight1 (number)Execution unitComputer animation
54:29
Computer animation
Transcript: English(auto-generated)
00:04
OK, so thank you very much for coming along this morning. My name's Gary Park. My contact details are up there. If you have any questions, feel free to reach out. I'm here to talk to you about a tool, a build orchestration tool called Cake. And my aim today is to help answer
00:21
some of the questions surrounding what is Cake, why you would use it, and also provide some demos at the end as to how you can actually use Cake to achieve that cross-platform build automation that a lot of us are now wanting to achieve with the advent of things like .NET Core and platforms and environments,
00:41
such as Mac and OS X, that we want to target. So the first question that we really want to answer is, what is Cake? So first up, for those of you who have come here expecting actual Cake, I apologize. There is no Cake. Trust me when I say you wouldn't want any Cake that was baked by me, OK?
01:01
What we are here to talk about instead is this Cake. So first and foremost, Cake is a open source project. It's been around since 2014. It's hosted on GitHub. It was started by a Swedish colleague of mine called Patrick Svensson. And then it was later joined by another Swedish colleague
01:22
called Matthias Karlsson. I then joined the project. So yeah, full disclosure, I am a member of the Cake contribution team. If there is anything wrong with Cake, it's probably my fault now. So feel free to pick me up on that. I joined the tail end of 2015. It's a reasonably small project,
01:41
but it is growing in popularity. We have almost 400 pull requests into the project with 60 different contributors, as well as over now 40 third-party add-ins for the Cake ecosystem. And I'll come to that in a bit, what that actually means. We're happy to say that as of today,
02:02
we've got about 55,000 downloads on YouGet. So again, we're happy that it's an evolving project and people are taking an interest in it. So trying to answer the question about what is Cake, this is the definition from the cakebuild.net website that I encourage you to go and have a look at. So what we're trying to say is it's a cross-platform
02:21
build automation system with a C-sharp DSL to do things like the compiling of code, the copying of folders, and so on. But at the end of the day, what does that actually mean? What we mean by that is that Cake is an EXE. It's just an executable that you would run as part of your build process. And it will take as an input a build.cake file.
02:44
And that build.cake file will have the definition of what your build is. It's a script processing engine that uses Roslyn and or the monocompiler under the hood to take that script, compile it down into an executable piece of code, and then I'll run that against the platform
03:00
that you're running on. The reason that we have both Roslyn and the monocompiler just now is just to allow that cross-platform utilization. At some point, we will be switching to just Roslyn once the underlying Roslyn scripting engine become fully cross-platform. We'll be switching to that in favor of using mono.
03:22
But that's a step down the line in terms of the roadmap. So before I go too much further into what that actually means and what Cake actually is, what I want to make sure is that we're all talking about the same thing in terms of what is a build.
03:41
So for me, a typical build workflow starts like this. We have a build. We want to compile something, whether that's out of Visual Studio, whether that's out of MonoDevelop, whether that's out of some other IDE. We have something that we want to build. In order to do the build, you might have something like a package restore step.
04:01
If you have NuGet packages within your solution, you have to first restore them as part of the build in order for the build to succeed, because you've taken those dependencies. On top of that, you might want to run unit tests. Because as everyone knows, there should be unit tests in a project. Not everyone has them, but that's the ideal, is you have some unit tests to go with your project.
04:21
In order to complete the build, you might have something like a clean step. A clean step basically just tidies up the underlying folder structure to remove any artifacts as part of the build process. Because the last thing you want is a build succeeding only because the last one succeeded. So you have a clean step. On top of that, you might have some test coverage.
04:41
Because what's the point in running tests if you're not actually looking at the results of those tests and making sure that you're either improving or things are getting worse? Then, if you are, depending on what kind of developer you are, if you're like me, you want to run some sort of stack analysis on your code to make sure that everything is meeting the standards of your project team.
05:03
So you might use tools like StyleCop, or JupFinder, FXCop, or InSpecCode. Those are all utilities that will basically look at your code base, make sure that all the line endings are the same, that you're not doing anything that you shouldn't be, and so on. And you might have a package step.
05:21
So what's the point in building something if you're not actually going to make it available for consumption elsewhere? And then there might be a final step, which is the publish step. So that's to take the output of the build, whether it's an MSI, whether it's a NuGet package. Whatever your output is, you might want to push that somewhere so that other people can consume it. Especially if it's a paid-for product,
05:42
you want to make sure that it gets there. So what I'm hopefully describing there is something that is common to everyone. It's a fairly typical workflow. Obviously, your steps might differ. But what I'm going to show here is hopefully that Cake can help you to fulfill that workflow in a common way.
06:03
Once we get into the innards of Cake, what Cake's going to do is it's going to create what's known as a directed acyclical graph of all of those tasks. And it'll make sure that it's part of the build process that each of those tasks is run at least once as part of the build.
06:22
So with that in mind, just a quick brief overview of what Cake actually is and what it does. So Cake, as I said, is an exe. That exe takes as its input this build.cake file. I'll show you some examples of what the build.cake file is and what it means as we go through this. In addition to the build.cake file,
06:42
Cake accepts a number of arguments into the raw cake.exe, as well as via Invite Invadables and or a configuration file that you can actually specify within your repository as well. What that allows you to do is fully customize how Cake is going to work.
07:01
Once you've got both the cake file and the arguments being passed in, as part of your build script, you have the option of using what we call preprocessor directives. What they allow you to do is to add any tools or add-ins into your build workflow. Because as I mentioned before, if you're using something like Inspect Code,
07:21
you need to get that tool from somewhere. We don't recommend that you put those tools directly into your source control repository, because one, it makes your source control repository big, and you don't need to. You can get it from elsewhere. So you can use the preprocessor directives to pull those from some source on the internet and make it part of your build.
07:42
In addition, because it's just C Sharp, if you wanted to reference just a DLL or a NuGet package to consume the ability, for instance, for let's say you wanted to use something like JSON.net, you wanted to parse some JSON as part of your build process, you can have a direct reference to the Newtonsoft DLL.
08:04
And then within your cake file, you can just write the normal C Sharp that you would for parsing that JSON and using it as part of the build process. So once cake's got all of those things, what it's going to do is it's going to spit that out to either Roslyn or the monocompiler. It's going to take that script,
08:20
and it's going to make an executable piece of code out of it. Obviously, at that point, if there are any syntax errors or any problems with the script, it's going to fail. It's a compilation step. So it will fail as part of the build. But you'll get notified of that just in the standard way with a stack trace and some pointers as to how to correct that.
08:43
Once all that's done, it then actually executes the build. And the output of that build is literally anything that you can think of. So whether it's, as I said, it's an EXE, whether it's an MSI, whether it's a NuGet package, whether it's a deployment to Azure, to Amazon,
09:01
literally anything can be done as part of this build process. So the world is your oyster. So I can't stress enough that the familiarity that you might have in C Sharp also extends directly into the build.kick file. So whatever you can do in C Sharp, you can do within the build script as well.
09:20
So the next question that you might be asking is, well, you've spoken about all these tools and what you can do within the build process. So what tools can actually be used with kick? And I like to show this in this form. So the items that are appearing here in the black text are all of the tools that we have available within core kick.
09:43
So as soon as you have a reference to kick, you have the ability to use all of those tools. The ones that are showing up in blue are ones that have been submitted via our community members. So they've come as direct add-ins to the project. That's actually where I got started in the project.
10:02
I'm also a contributor to an open source organization called Git tools that have tools like Git version and Git release manager. I saw that cake as a product didn't have the ability to run those tools. Initially, I started using the extension points within cake to have those as third-party add-ins into the product.
10:23
But they've subsequently got merged into the core product as well. So what we've got in here is the ability to do things like we cover all the unit testing projects and the ability to run test coverage. We also have, if you notice in there, we have things like Slack and Gitter.
10:41
Because as part of the build process, you need to know when something's gone wrong. And with the explosion of the use of Slack and things like Gitter for communication channels, you can post a message directly into a Slack channel or a Gitter room to notify people that something's gone wrong with the build. So although there's a lot up there, hopefully you'll see that there are some that you're already
11:03
using today. And you'll immediately be able to start using within cake. And on top of that, as I said, if there's something that's not in there that you actually require, the extension points within cake make it really simple to add that in. So the next question that you might be asking yourselves is, OK, but why do I need it?
11:21
So what I want to emphasize here is that for me personally, cake is all about the familiarization with C-sharp. But on top of that, it's the ability to have a build system that is both maintainable and consistent across those different environments. So what I mean by that is if you're just in Visual Studio
11:41
and you're doing the Control Shift B to build the solution and that's your workflow, then that's great. The problem stems from the fact that if you go on holiday and someone else has to take over the project and it doesn't build on their machine because they don't have an SDK installed or they don't have a tool installed, then the build fails. Then that's where the communication channels break down.
12:02
So having something like cake, which allows the build to be orchestrated in such a way that it can run on any machine, it takes that concern or that problem away by making it or kind of forcing you down the path of making it work on every machine. But again, it's just in C-sharp,
12:21
and that's really the big draw for it. The other part of the process, as we've mentioned, is that within Visual Studio, if you're just doing a build within Visual Studio, you might be using a test runner like ReSharper or nCrunch to run the tests. But again, you want to take that out of Visual Studio. You want to have that being common for everyone
12:42
to the point that you could actually hopefully run the build on a machine that doesn't have Visual Studio installed. You want to be able to run the build just with the basic SDKs and the tools installed rather than that dependency on all of those property. And probably the final, most important part is that we want to eliminate the problems with human error.
13:04
We all make mistakes, but by putting it into a scripted process, then you're allowing the computer to take over at that point. You're not worried about, oh, did Bob remember to do this step when he did the build, or did Bill remember to do this step? It becomes a documented part of your process,
13:20
because it's part of your source control repository. So hopefully that answers the question on why do we need it. The other kind of questions that I want to hopefully answer today is, what are the core philosophies of Cake? Because Cake as a product has a number of ideas about what the build processes look like, but we also don't want to force those upon you.
13:42
We want Cake, we can make suggestions, but Cake is flexible enough to allow you to run the build however you want. But some of the core philosophies of Cake are it should be non-intrusive. So some of the other build processes or build pipelines that you might have used require modifications to things like your CS Proj files in order for it to work.
14:04
Cake is fully non-intrusive, and what I mean by that is it's a standalone build.cake file that will reside beside your code, and that's it. It doesn't require any other tie-ins to the system. So what that means is, or what we like to say is, you can start using Cake without telling your project
14:21
manager about it, and once he's seen the power of what cake can give you, you can then just slot it in because you haven't actually affected any of the rest of your process. The other thing we like to say is it should just work. We have tie-ins and aliases for all of the most common tools. They're being run on a number of different build systems now.
14:41
For instance, we use Cake to build Cake. So we like to do that because we can then obviously see any problems that are creeping through. So if things aren't working, there's something wrong with Cake, obviously, but we test it to an extent every time we do a release, so we hope it just works. We also want Cake to be highly configurable.
15:02
So what we mean by that is, as part of the build process when you need to change something, you can do that. It's highly configurable, and with the most recent release of Cake, it's actually completely modularizable now as well, so that if there's something within Cake that you don't like, you can rip that out and replace it with your own specific implementation
15:24
of that particular part of Cake. The other core tenant that we like to suggest to people is that there should be no binaries checked into source control. Simply put, they're not required. You want to have them coming from somewhere else, and that goes for Cake as well. And what we'll come on to as part of the demonstration
15:40
is we'll show how we, as a product, suggest that you bring actual Cake, the Cake.exe, into your pipeline. As I said before, we want it to be easy to implement your own tools, and I can vouch for that because that's where I started. And the final tenant is that we want the build to look and behave the same regardless
16:02
of what operating system you're working on or what environment you're running on. And the most easiest way to show that is by showing you this. So that is on our GitHub repo. It's within the readme.txt. We build Cake with Cake on eight different CI servers,
16:23
and we run it on and across three different operating systems. So you might think that that's a little bit excessive, but there are certain parts of the tooling that behave differently depending on what CI server that it's running on, what continuous integration server it's running on. For instance, something like the unit testing framework
16:41
nUnit, it knows that it might be running on something like TeamCity, so it automatically pushes test results into the TeamCity system via what it calls service messages. So we like to make sure that Cake, when it's utilizing these tools, continues to function as we want it to. The eagle-eyed amongst you might
17:00
notice that the Travis build was failing when I took that screenshot. That was to do with NuGet. Travis and NuGet aren't getting on very well just now, but I wanted to leave it up there just to show that we're not infallible to the build processes. We're still subject to external failures as well. But we have actually put some additional retry logic now
17:22
into our own build so that if the Travis build fails, we'll retry it again as part of the build process, because typically it's the NuGet package restore that's failing. So we've just added in the Polly tool, which will automatically retry that NuGet package restore as part of our build. And nine times out of 10, it continues to work as expected.
17:44
The next question that I'd like to address is, can't I just use Fake, or Make, or CMake, or MMS build, or NAND, or SAKI, or BOW, or any one of these other existing build tools? The simple answer is, yes.
18:02
I'm not going to stand up here and tell you that you have to use Cake. If you're already using those tools, then continue to use them. I can't force you to use Cake. I would like you to use Cake, but I can't force you to. But what I like to say here is that we've heard through our community members and various conversations that we've had,
18:21
is that there's this concept of, well, if you're doing a C-sharp development project, then using the build system to learn another language is a good way to do it. So if you wanted to pick up PowerShell, for instance, you might want to use SAKI. Or if you wanted to pick up F-sharp, then you might want to use Fake as the build system, because then you're kind of being
18:41
forced into that different language and it's a good way of learning. And I fully agree with that to an extent. The extent is, when that build fails, you then have to do a mental mind switch into that other language to fix it. And the problem that I've seen, even with my own company,
19:01
is that you become that one person who knows how to make the build work, because you're the one who put it in place. Using something like Fit Cake makes sense if you're doing a C-sharp project, because you don't then have that mental mind switch between the two languages. You simply then have, you're doing a direct port from one language to the other, and you're fixing the same problems.
19:21
So what I would say is, if you're doing a PowerShell project, use SAKI. If you're doing an F-sharp project, then use Fake. But if you're using a C-sharp project, then use something like Cake or Bio or one of the other C-sharp-based systems that are out there. But what I try to avoid is that mental mind switch that has to happen as part of the build process.
19:43
So without further ado, what I'm gonna then do is I'm gonna switch onto the demos, because that was just a very brief introduction. I think the heart of this talk is really about the demos and what you can actually achieve. So what we're gonna do is, what we're gonna try and do as part of the demonstrations is we're gonna take that typical build workflow
20:01
that I spoke about earlier, and what we're gonna try to achieve are the ones in orange here. So we haven't really got time within the time allotted to do everything, but hopefully, if we can get those ones done, you've got a clear indication of how you can start building with Cake and then start plugging in the different parts
20:20
of the build process that you want. If you're interested in the demos I'm gonna show you, you can get them from there. It's a very simple GitHub repo, but it's got all the steps that I'm away to work through so you can take them away and work them if you need to. So with that in mind, let's jump to demos.
20:42
Okay, so just a couple of quick notes about the demo that I'm away to show you. I didn't want to rely on the internet connection at NDC, although I was told it was really good, I didn't want to rely on it. So what I've done is I've used some of the things that I spoke about in terms of the configuration, and I'm running Cake in essentially a offline mode.
21:04
It doesn't require an internet connection in order to run, so I've used some configuration options to make it run completely locally. For instance, I'm using a Nexus repository, so I've got a local NuGet repository for all the packages that I'm away to pull in.
21:21
I don't need to go out to NuGet.org. But what I will say is that all of the commands that I'm away to run and all of the scripts that I'm away to show you will work in that obviously online environment. I'm just running them locally just so that I didn't have to worry about the demo gods making it not work.
21:41
Okay, so where we're going to start is if we go back to our demonstration here is we're going to start the package restore step. So why we need to do that is that if we jump to Visual Studio here, what I've got here is quite simply the most amazing project you're ever going to see.
22:01
It's not really. It's literally the standard ASP.NET web application template that comes with Visual Studio out of the box. All I've done is slightly customized it to make it so that I've got a test project that's doing a few tests against some of the home controller.
22:20
And also I've made it so that there's a third-party library in there. This cake.sample.common, that's a third-party library or a common library that's shared between the web application project simply so that I can show how we're going to do some NuGet packaging. I'm going to package up that sample.common into a NuGet package as part of the build process. The reason that ReSharper and Visual Studio
22:43
are literally screaming at me right now is because I've made it so that none of those NuGet packages have been restored. So it's running essentially with all the references not there. So both Visual Studio and ReSharper are saying to me, you need to fix this. But again, we're not in Visual Studio at this point.
23:01
We're going to do it all from the command line using our cake script. And we're going to make that build work effectively. But I just wanted to show you what we're actually building. So the tool that I use for what I'm doing, my build script, this is VS Code. What we've actually got in here is cake has a VS Code extension,
23:23
which means we've added in some custom functionality to VS Code specifically for cake. One of those is these commands. So if I go up to here, hopefully you can all see that. If I type cake here, what we'll see is that there's two custom commands in there.
23:41
One is to install what we refer to as the cake bootstrapper. And the other is to install a configuration file. The configuration file is what I spoke about before. You'll see that I've actually got one in my project here already. That's simply controlling where cake gets some of its core components from.
24:00
So again, I've made that local so it runs locally against my local host. But that typically wouldn't be required unless you wanted to change that functionality. So what I'm going to do here is I'm going to type cake again, and I'm going to install the bootstrapper. So what it's asking me for is whether I want a bootstrapper for Windows
24:20
or whether I want a bootstrapper for Linux or OS X. In my case, I'm on Windows. So I'm going to go ahead and select that option. So what we're going to get there is a notification to say that a bootstrapper file has been downloaded. And as you'll see over here, we've now got a build.ps1 file. So this build.ps1 file is the one that we give you
24:43
to get started with. It's fully expected that this bootstrapper file will need to be customized by yourselves because you'll want to do things as part of your project setup that we don't. But this is our best attempt or our best suggestion as to how to get started with it. So I'm not going to go through this in too much detail,
25:04
but just so you understand what's going on here, this bootstrapper is going to ensure that we've got the dependencies in order for cake to function. So we need to download the cake.exe. So for instance, you'll see in here
25:20
we... Where did we download cake? So once we've got the cake.exe installed, which we do as part of the tool resolution, we'll have that cake.exe ready to be executed. So this is really just a setup stage. Once you've got this configured,
25:41
you'll never likely need to touch it again. And it's the exact same thing for the... It's the exact same thing for the bash version, but all we're giving you here is the bash or the Linux or OSX equivalent of doing that exact same thing. So the reason that we have two is obviously
26:02
if we're running the same build.cake file on all of these different environments, we need some way of kicking that off. So if we're running our build on AppVR, which is a Windows CI system, we'll target the build.ps1 file. And if we're running on something on Travis, we'll target the build.sh file so that it does the bootstrapping for us.
26:23
Okay. Once we've got that bootstrapper in place, what we'll do is we'll just close that. No, we don't want to save it. We'll just add in a straight up build.cake file. That's not going to be right. Let's rename that.
26:41
So we're going to add a build.cake file. So this is obviously going to be empty when you first start. So what you want to do is you want to start populating this with the tasks, those directed acyclical graphs that I spoke about. You want to start stubbing out those tasks as part of the build process. So as you saw there, my typing isn't very great
27:01
when I'm standing up here. So I've got a number of code snippets that will help me enter that into here. So I'm just going to start doing that. So what you've got here is kind of the most basic build.cake file that you can kind of start with. So what we've got here at the very top on line one
27:22
is I'm accepting arguments from the command line. So this is cake's way of saying, find an argument called target from the command line. If there isn't one, default that to the default target. So if you wanted to call cake with a target of, say, NuGet package restore, then that would be the task that it would target
27:42
as part of the entry point of the build system. At the bottom there, we've got on lines nine and 10, we've got what is the definition of that default task. And all we've got there is a dependency and is dependent on to say what should run when that default task is started. So in this case, what's going to happen,
28:01
if we refer back to here, we want, as part of the default build, we want that package restore to run. So that's what's happening here. We're going to say, pass in the... Or rather, we're not going to pass in a target. It's going to run the default, and then it's going to run the NuGet package restore step. Now if we just go ahead and save that,
28:23
now what I could do, and this is another reason to start using VS code, is that with the latest release of VS code, there is now a terminal, an interactive terminal within here. So what I can do is I can actually just say, run that build up PS1 file. And you can see the build executing there.
28:40
I'm not going to use that because it's kind of difficult to show you that and also edit the code at the same time. So I'm going to just use a straight up PowerShell window here. So I'm going to run that same build. So what you'll see here is that actually it's gone through the build process and it's output that it was successful. Green, obviously successful.
29:01
But we haven't actually done anything yet. All it's done is it's ensured, so that bootstrapper has ensured, if we jump to this folder over here, that bootstrapper has ensured within this tools folder, which is a convention that we start with, but again, that's configurable. It ensures that the cake.exe has been downloaded. So that bootstrapper went off to NuGet,
29:21
it downloaded the cake.exe and made it available in this tools project, in this tools folder, and then it's executed the cake.exe, passing in the build.cake, again, a convention, and it's executed the build. So we haven't actually done anything yet. What we have done is we've started that process of making that all work.
29:41
So if we just run that again, obviously it doesn't need to do that, some of those bootstrapping steps anymore, so the build is going to be that bit quicker this time, but just understand that that's already happened for us. So what we want to do now is we actually want to do something within this NuGet package restore step. We want to make a call out to NuGet.exe,
30:02
we want to pass in the location of the solution file, in this case, the one that I've got in Visual Studio, and we want to do a NuGet package restore. So for those of you who have done that, at the command line, we all know it's just NuGet, restore, pass it in, but what we're trying to do here with Cake is we're trying to get to a point where
30:20
we're not worrying about the actual command line arguments. We want a type safe way to make that happen. We want to do it in a way that we don't have to remember all of the specific command line arguments. We want to have it just so, again, it just works. So what I'm going to do here is I'm going to go in my second demonstration here.
30:42
So this is what it looks like. So we've got a command alias, a method alias, for NuGet restore, and all I'm doing is it's accepting an input parameter, which is the location of that solution file, and that's literally it. That's all we need to do to kick that part of the process off. So to show that there's no kind of smoke and mirrors going on,
31:02
I'm going to go to the source folder. Notice that there's not a packages folder at this point, but if I go over here and run that build, what it's going to do, you're going to see this wall of text, and that wall of text is the 47 packages that the default ASP.NET template needs in order to build.
31:22
So what that's done now is it's taken all of those NuGet packages, again, in my case, from my local NuGet feed, and put them into the system. So now they are available to us. If I run the build again, we're not going to see that big wall of text anymore because those packages have already been restored. So again, incrementally, the build is going to get quicker,
31:41
but again, if I were to remove that packages folder and make it a little bit harder for the build system, then run the build again, then we are going to see that big wall of text because we need to restore those packages. So again, we're scripting it out. We're making it so that one person
32:01
doesn't have to remember to do all these steps. We do that as part of our build process. Now, don't get me wrong. This happens for you automatically within Visual Studio when you do that Control-Shift-B to do it within Visual Studio, but we're stepping away from that environment, and we need to take ownership of those particular tasks. So if we jump back to here, what we're going to do now is we want to actually run a build now.
32:22
We want to build that solution and look at the output. So again, if we go back over here and have a quick look in here, then there's no bin folder. This project hasn't been built yet, so we want to build it as part of our script. So what we're going to go, we're going to go back to here, and we're going to go at the top here, and we'll start demo two.
32:41
So what I'm going to do is I'm going to add in an additional argument up here, because as you know within Visual Studio, you can specify whether you're doing a debug build or you're doing a release build. So the same process or the same options need to come through cake. We need to specify whether we're doing a debug build or we're doing a release build. And we can take that as an input argument. So again here,
33:00
I'm going to look for an input argument called configuration, and if there's not one, I'm going to default to it being a release build. With that in place, I should be able to come down here and do demo two, and I'm going to do the exact same thing as I did before. So there's just a method alias again for MSBuild, and all I'm doing is I'm passing in
33:21
the location of the solution file. Now some of you might be thinking, well, that's all well and good, but I need to be able to set the treat as warnings error as part of my build, or I need to specify the specific MSBuild version that I want to use. So that's where the configuration options within each method alias comes from.
33:40
So if I rewrite that as this, then what we're seeing here, using this MSBuild settings class, so I'm just newing up a new instance of that settings class, and I'm then going to set multiple properties, some with extension methods, but I'm basically saying I'm on Windows. I want to treat warnings as errors, and I'm using that specific version of the MSBuild tool,
34:00
and I want to set verbosity to minimal and so on. So all of these things are available to be set, and where I would direct you to for more information on that is the help documentation that exists on cakebuild.net. So what you're seeing here within the MSBuild aliases, there's an example there of what you can do, and then if we jump over here
34:20
on the MSBuild settings page, we'll see all of these properties that we can set on MSBuild. So all of those are then directly translating to command line arguments that are passed to the underlying MSBuild.exe as part of the build. So with that in place, what I need to do, before I forget, is I need to change my default task
34:40
to now take a dependency on the build task, because as part of that graph that we're building up, we're now wanting to run the build, and then the build takes a dependency on the NuGet package restore, and that's what this line is doing. Now if we jump back over here and have that folder open as an example, we're going to run the build. It's not going to do that in NuGet package restore now
35:01
because we don't need to, but it's going to do the actual build steps. So you see here it's doing the build, and then we'll see we've now got a bin folder, so it's now actually running the build. So if we let that finish out, we've now got the artifacts of that build are now within here. It's compiled all the EXEs and the DLLs that go with that project.
35:21
Now the eagle-eyed amongst you, or the concerned amongst you, might be thinking, well, in this bold new world of .NET Core and ASP.NET Core, we haven't quite yet got an MSBuild Core. There is one, but it's not quite there yet in terms of what we need. So the immediate question is how do I run this on Travis
35:41
because you're calling MSBuild. MSBuild doesn't work on Travis. So that's where the flexibility of K8 starts to come in again. If we use this example, what we're showing here is that within this build step, I might want to have a simple if statement. So that simple if statement says if I'm running on Unix,
36:00
so either Mac or OS X, I want to use the XBuild tool rather than the MSBuild tool. So the XBuild will work on those platforms. So obviously K8 can't do everything for you. It's not going to know which tools run on which environments. So there is going to be some element within your build script of understanding the build pipeline,
36:22
understanding which tools run on which environments, and then taking the necessary steps to ensure that they run in the correct instances. So what I'm showing here is with the addition of the is running on Unix method, we can then make an informed decision about which tools we want to run. And it's the same thing. You can do it in reverse. There's an is running on Windows,
36:41
and there are other steps you can take in terms of ensuring that one particular build task runs on those platforms as and when required. So if we just leave that in there, save it, and then run it again, the exact same thing should happen because I'm still on Windows, so I'm still running that same MSBuild task, and it completes as required.
37:03
Okay, so moving on. The next thing we want to do is we want to run some unit tests. So we want to run some unit tests. So the unit test runner that I'm going to use is, I think it was XUnit. Let me just check that. So I've got some unit tests in my project. So I need an XUnit task. So this is showing, again,
37:20
we've got an XUnit 2 alias. It takes a number of arguments. So those of you who are familiar with XUnit will be familiar with these things. So here I'm just setting a couple of things like the output directory, what kind of report I want to be generated, and where I can find the DLLs, the test DLLs that I actually wanted to execute. So what I've got here is I need to say
37:42
that I now want to run this one as part of the build. So I'm going to change that over there. So as part of that graph, the unit test is going to run the build, and the build is going to run the NuGet package restore. So if I go ahead and run that, I'm going to get a failure. And I hope I'm going to get a failure.
38:00
I should get a failure. Yes, I got a failure. Now that's expected. So everything that I've showed you so far, the NuGet package restore and the MSBuild, the tools, the underlying tools for both of those aliases are already on my machine because the bootstrapper downloaded NuGet to EXE for me, and I have Visual Studio installed, so I already have MSBuild installed. XUnit, I don't have installed.
38:22
So this is where the preprocessor directives come into play. I need my cake build process to grab that tool and make it available for me as part of the build. So if I go over here, I'm going to use the tool resolution syntax. So what that's saying is
38:41
hashtag tool NuGet, and then so that's specifying that the tool comes from NuGet, and that's where I can find it. Now, again, because I'm running locally, I want to have a slightly different syntax. I'm going to use this. So this is just showing the flexibility of that URI syntax that we're using there. I want to have that package
39:01
come from somewhere else. The default would be for it to come from NuGet.org, but I want it to come from my local repository, so I've changed that syntax up slightly. And if I wanted to have a specific version of that tool or to use a pre-release tool, then again, there's additional arguments that you can put onto the end of it to make that happen. So with that in place,
39:20
if I run the build again, this time it will download the tool that is NUnit. So we'll have the XUnit tool console runner is now available in my tools folder. So Cake knows about it now, and it's now attempted to run the unit tests. But again, it's failed. And it's failed if you were to read the stack trace here
39:43
and do some googling as I needed to when I first tried to do this demo. You'll realize that as part of the output or the running of that XUnit tool, we specified that the output directory should be a folder called dot build slash test results. The XUnit runner actually assumes
40:01
that that folder exists. It needs to exist on the file system in order for it to output the file there. So what we'll see is if we go up here, we don't have a dot build folder, and we don't have a dot build test results folder. So it's therefore failed. So again, we need to take ownership of that as part of our process. So if I go up here
40:20
and add in a clean task, and so all that's doing is, again, it's using a method alias that we have available. So all it's doing is saying, for every folder that I put into this clean directories method alias, make sure that two things happen. One, that that folder exists, and make sure that it's empty,
40:40
because again, it's part of the build process. We want to make sure that there are no artifacts left as part of the build. So with that in place, what I need to do is now my X unit test is dependent on two things. So I'm just gonna say it is dependent on the clean task. And if I go back to here,
41:01
and I go back to here, what we should get this time is it'll run through the build, it'll run X unit, it'll create that build folder as part of the build, and it'll put the output of the test results into there. So what we'll see in here is I've got three tests, and because I'm an amazing developer, all three tests passed,
41:21
and I can go home knowing that my build works. So that's that part of the process. So if we go back to here, the last step that we're gonna cover is the NuGet packaging. So as I discussed in my Visual Studio project here, I've got this cake.sample.common DLL
41:43
that I want to wrap up as a NuGet package, because I want to share that within my project teams. So I want to do that using the NuGet package step. So if I go back down to here, I've got a new package step. And what I've got here,
42:01
and you might be immediately thinking, Gary's gone nuts. What is all this stuff? Because this is meant to be really easy. And what I'm trying to highlight here is that, yes, it is really easy. There is just a NuGet package. There's a NuGet pack alias that will just take as an input the NuSpec file that you want to package. But what I'm showing here
42:20
is that there's complete flexibility in terms of how Cake operates, is that if you don't want to have that NuSpec file, or you know that that NuSpec file needs to be created each and every time that you're running the build process, you can have Cake specify all of those properties as part of the build, and then pass all of those NuGet pack settings into that NuGet pack,
42:42
and then just have it create the build. So what you won't find within my demo project, if I go up to here and look at the source and look at the Cake comment, then there is no NuSpec file in there. So I'm fully running the packaging of that NuGet package from the build process. It doesn't rely on the underlying system.
43:00
But what I'm just trying to show here is the flexibility and what you can get it to achieve. So what we'll need to do here, again, I'm not going to make the same mistake I did before. I'm specifying that the output directory of that NuGet package should be a NuGet folder within the build output folder. So I'm going to go up here, and I'm going to change my clean task to include, if I can type demo,
43:23
I'm going to change it to extend that clean task to include another folder, which is the build NuGet folder. And I'm going to go down to the bottom here to specify that the default task now takes a dependency on package. So if I go over here
43:41
and show the output folder, which is build, I go back over here and run the build. And what we're going to do is we're going to do all the steps that we did before. It's still going to do the NuGet package restore if required. It's going to do the build. It's going to do the X unit test. And it's also going to package up. And into this NuGet folder, I've now got an up keg, as they're called. And if I open that bad boy up,
44:01
what we're going to see in here is it's got the version number that I specified. It's got the release notes that I specified. It's got the copyright that I specified. So all of those things came from the build script. Now the final demo that I wanted to show before we go back to the slides is... So what I've showed so far is...
44:22
Sorry, question. So the question is why do I not specify a version number into the build output so that it segregates in that way?
44:42
You certainly can do that. I mean, typically, when I'm doing a build, I use a tool called Git version that asserts the semantic version based on the commit history into the repository. So I'm always asserting that. If you wanted to, I mean, keg actually does that. So if you actually look at the keg build script within our build output folder,
45:02
we do take a version number and append that into the build output folder. So you certainly can do that. Again, it's flexible. I mean, you can do anything you want. So if you're interested in that, take a look at the build.keg file on keg itself, and you'll see that in its artifact folder, we do include the version number so we can segregate in that way.
45:21
So you certainly can do that, yeah. I mean, the question I would ask is why we're running two builds on the same machine at the same time. That would be another question.
45:44
They check it in, but if you've got... So the question is what happens if there's kind of two builds running at the same time? On any sort of typical CI server, the build agent is only running one build that's in the queue at one time. So your continuous integration server would take care of that. Unless you've got multiple agents, at that point, the files are all local to that agent.
46:02
So the queuing system within the CI system would take care of that. We can talk about it some more afterwards if you've still got some questions. So what I wanted to show was as part of this demo, what I showed was that as you're creating the build script,
46:20
you might run into issues. You might run into issues with the tools that are missing, or you might run into issues with syntax, or you might run into issues where something just isn't working as you would expect it to. So what I would say is that as you move these builds onto some sort of CI system, you want to have some sort of logging and diagnostics in place
46:41
so that when you're running on something like TeamCity or Jenkins or Travis, you can look at the build log and see what's going on. But what I would like to show you is we have recently added in the ability to do debugging of these cake scripts. So because it's just a C-sharp script, we can have that within Visual Studio and step through the build using Visual Studio.
47:03
So when you're first creating the build, it becomes easier to figure out what's going on. So what I'm going to do is I'm going to go up to here, into my NuGet package restore step, and I'm just going to use another one of the preprocessor directives that we've included, which is just the break. So what this is going to say is run.
47:22
When you see that, if there is a debugger attached, then stop at that point in the cake build. So I'm going to jump to here, and I'm going to run cake directly this time. I'm not going to use the bootstrapper. I'm going to use cake directly. I'm going to pass in that build.cake file,
47:41
and I'm going to pass in debug. So what that's going to do is it's immediately going to say attach a debugger to the process it's just started. So it's instantiated cake. It's passed in, or it's created a process to go with that. So if I jump over here to Visual Studio, and I go debug,
48:01
attach the process, and the process ID there was 4628, so it's that one. If I go ahead and attach to that, what it's going to do, it's going to attach the debugger to that process that has been instantiated. It's going to load up that build.cake file, and it's going to step on that preprocessor directive that is the break one. So what you're looking at
48:20
is it's still saying break, but in the compiled version, it's got the system.debug.debugger attach, or the launch debugger. So at this point, I can just F10 through the build. So if I go back to here, what you'll see here is that you're still seeing the output as it's happening, but we're stepping through it within Visual Studio.
48:41
So if I step through this again and do the actual build, so we've got that if statement there, so we know that we're running on Windows, so we're going to run MSBuild, jump back to the PowerShell output, we see the build happening, but you've got the option within Visual Studio to step into that. So the prime example of that is if I go back down to this one, I set a break point here,
49:01
and I let that run until we get to the new get package step, I can set a very quick watch on this, and then in here, I've got access to all of those properties that I've set. So again, when you're first creating the build script or you're trying to debug something going wrong with the build script, so it's not quite working the way you want it to, then you have the option of stepping into it
49:22
with the debugger within Visual Studio. Okay, that's one of the benefits you kind of get for free because it's C Sharp. Okay, so I'm just going to jump back to my slides here. Oh, I did that wrong. I should have done a control F5 there. Let's do that again.
49:44
I've lost that. I go back to my demo slide here. Okay, so the last thing I wanted to talk about before I take any questions, if there are any, is I wanted to announce some news associated with Cake.
50:03
So as of today, Cake is now a member of the .NET Foundation. So those of you who are not familiar with the .NET Foundation, it is an independent organization that's trying to foster open development in the .NET ecosystem. It's got projects already in it. For instance, Identity Server, MVVM Lite, .NET Core,
50:24
and ASP.NET Core. So we're very happy to be joining that foundation because we think it will obviously bolster the Cake profile. People will hopefully become more familiar with what Cake is and what it does.
50:42
The blog post that I've linked to there might not quite be up yet because they're tying it in with this talk that's happening here, but it will be up there at some point today. So like I say, we're very happy to say that we're now a member of the .NET Foundation. So we've got about five, ten minutes left.
51:03
So if there are any questions, I'll take them just now, if anyone has any. No questions? Yes.
51:23
Could I just throw out my old build server or build system? From a purely personal standpoint, sure. Why not? Depending on what build system you're using, what are you using just now then?
51:43
So Cake is not going to replace TeamCity. TeamCity is the CI server, but within TeamCity, what you will typically do is you will have build steps. So within your CI server, you'll have steps within TeamCity, and that step may be the exact same steps that I showed here. So you might have a step that's doing the NuGet package restore.
52:01
You'll have a step that's doing the MSBuild. You'll have a step that's doing the unit testing. None of that goes away. It's just that you've moved that into the build.cake file. So what you're effectively saying is to TeamCity, you'll then have one step within TeamCity, and within TeamCity, all you're going to do is run the build.ps1 file.
52:21
You're going to run that bootstrapper file, and it's going to take care of all those steps because, simply put, I love TeamCity. That's what I use, right? I'm not going to throw TeamCity away because I need and I want that because it's still orchestrating the build queue for me. But what I'm doing is I'm taking some of the weight away from TeamCity and then just having it all contained within my one script.
52:41
So the benefit of that is, when you go fully cross-platform, right, I want the same build to run on Travis. So that's where the bootstrapper comes in. You'll have the bootstrapper, the build.sh, that will run on Travis, which is running on Linux, or OS X, but it's still running the same build.cake file. So it opens up that option to run the exact same build
53:03
without having to recreate each of those steps within those CI servers. So no, Cake is in no way, shape, or form trying to replace TeamCity because TeamCity does a great job of what it does, and it does have those build steps that will do some of the work that we're showing here, but it does mean that you have to replicate those steps
53:21
on Travis or Jenkins or Bamboo or whichever other CI systems you want to run by putting it into the build.cake file, that commonality comes in so you can run the same thing across all of those platforms. So no, don't throw away TeamCity. You definitely want to keep using TeamCity. Okay? Any other questions?
53:43
Okay. If not, there's a couple of demo slides, a couple of resources there, just pointing you to the Cake documentation. There's a recent podcast that we did on the MS Dev show, and we've got a couple of blog posts out there that kind of just show how you get started with Cake.
54:00
So I'd encourage you to go and take a look at those. But if that's it, that's all I have to say, so thank you very much, and thank you for attending.
54:20
And there's also ones for chocolatey that I'm also involved in, so feel free to go and grab some stickers if you want some.