I have created a angular application using command ng new APPNAME
. I want to use cake build to deploy this application. Is it possible to use cake build? If so how? My end target is to deploy it to azure, but i need to do it with Cake build. I have uploaded all the source code to git repository.
Azure gives us the ability to deploy an application in a cloud environment easily and securely. In this article, I explain how to deploy an Angular application in a cloud environment in Azure.
Cake (C# Make) is a free and open source cross-platform build automation system with a C# DSL for tasks such as compiling code, copying files and folders, running unit tests, compressing files and building NuGet packages.
So building a plain vanilla app with the Angular CLI would look something like this
string target = Argument("target", "Build");
FilePath ngPath = Context.Tools.Resolve("ng.cmd");
FilePath npmPath = Context.Tools.Resolve("npm.cmd");
DirectoryPath outputPath = MakeAbsolute(Directory("./output"));
Action<FilePath, ProcessArgumentBuilder> Cmd => (path, args) => {
var result = StartProcess(
path,
new ProcessSettings {
Arguments = args
});
if(0 != result)
{
throw new Exception($"Failed to execute tool {path.GetFilename()} ({result})");
}
};
Task("Install-AngularCLI")
.Does(() => {
if (ngPath != null && FileExists(ngPath))
{
Information("Found Angular CLI at {0}.", ngPath);
return;
}
DirectoryPath ngDirectoryPath = MakeAbsolute(Directory("./Tools/ng"));
EnsureDirectoryExists(ngDirectoryPath);
Cmd(npmPath,
new ProcessArgumentBuilder()
.Append("install")
.Append("--prefix")
.AppendQuoted(ngDirectoryPath.FullPath)
.Append("@angular/cli")
);
ngPath = Context.Tools.Resolve("ng.cmd");
});
Task("Clean")
.Does( ()=> {
CleanDirectory(outputPath);
});
Task("Install")
.IsDependentOn("Clean")
.Does( ()=> {
Cmd(npmPath,
new ProcessArgumentBuilder()
.Append("install")
);
});
Task("Build")
.IsDependentOn("Install-AngularCLI")
.IsDependentOn("Install")
.Does( ()=> {
Cmd(ngPath,
new ProcessArgumentBuilder()
.Append("build")
.Append("--output-path")
.AppendQuoted(outputPath.FullPath)
);
});
RunTarget(target);
Which basically does
If you want to run the build and publish on kudu you can use the Cake.Kudu addin and KuduSync tool, dependencies are declared by adding tool
and addin
pre-processor directives like this:
#tool nuget:?package=KuduSync.NET&version=1.3.1
#addin nuget:?package=Cake.Kudu&version=0.6.0
And the publish task would look something like this
Task("Publish")
.IsDependentOn("Build")
.Does( ()=> {
Kudu.Sync(outputPath);
});
For kudu to know it should use a custom deployment script you need to add a .deployment
file telling it do so, which could look something like this:
[config]
command = deploy.cmd
And a custom boostrapper to install Cake i the kudu environment which could look something like this:
@ECHO OFF
REM SET Cake
SET CAKE_VERSION=0.23.0
SET CAKE_FOLDER=Cake.%CAKE_VERSION%
SET PATH=%~dp0\Tools;%PATH%
REM Cleanup any old Cake versions
FOR /f "delims=" %%c IN ('dir /AD /B "Tools\Cake*"') DO (
IF NOT "%%c" == "%CAKE_FOLDER%" (RD /S /Q "Tools\%%c")
)
REM Install Dependencies
IF NOT EXIST "Tools" (md "Tools")
IF NOT EXIST "Tools\Addins" (md "Tools\Addins")
IF NOT EXIST "Tools\%CAKE_FOLDER%\Cake.exe" (
echo Downloading Cake %CAKE_VERSION%
nuget install Cake -Version %CAKE_VERSION% -OutputDirectory "Tools" -Source https://api.nuget.org/v3/index.json
)
REM Execute deploy
Tools\%CAKE_FOLDER%\Cake.exe -version
Tools\%CAKE_FOLDER%\Cake.exe build.cake --Target="Publish"
Which basically just cleans up any old Cake versions and fetches 0.23.0 if not already installed.
The complete Cake script would look something like below
#tool nuget:?package=KuduSync.NET&version=1.3.1
#addin nuget:?package=Cake.Kudu&version=0.6.0
string target = Argument("target", "Build");
FilePath ngPath = Context.Tools.Resolve("ng.cmd");
FilePath npmPath = Context.Tools.Resolve("npm.cmd");
DirectoryPath outputPath = MakeAbsolute(Directory("./output"));
Action<FilePath, ProcessArgumentBuilder> Cmd => (path, args) => {
var result = StartProcess(
path,
new ProcessSettings {
Arguments = args
});
if(0 != result)
{
throw new Exception($"Failed to execute tool {path.GetFilename()} ({result})");
}
};
Task("Install-AngularCLI")
.Does(() => {
if (ngPath != null && FileExists(ngPath))
{
Information("Found Angular CLI at {0}.", ngPath);
return;
}
DirectoryPath ngDirectoryPath = MakeAbsolute(Directory("./Tools/ng"));
EnsureDirectoryExists(ngDirectoryPath);
Cmd(npmPath,
new ProcessArgumentBuilder()
.Append("install")
.Append("--prefix")
.AppendQuoted(ngDirectoryPath.FullPath)
.Append("@angular/cli")
);
ngPath = Context.Tools.Resolve("ng.cmd");
});
Task("Clean")
.Does( ()=> {
CleanDirectory(outputPath);
});
Task("Install")
.IsDependentOn("Clean")
.Does( ()=> {
Cmd(npmPath,
new ProcessArgumentBuilder()
.Append("install")
);
});
Task("Build")
.IsDependentOn("Install-AngularCLI")
.IsDependentOn("Install")
.Does( ()=> {
Cmd(ngPath,
new ProcessArgumentBuilder()
.Append("build")
.Append("--output-path")
.AppendQuoted(outputPath.FullPath)
);
});
Task("Publish")
.IsDependentOn("Build")
.Does( ()=> {
Kudu.Sync(outputPath);
});
RunTarget(target);
And output on the Kudu build running on your Azure web site would look something like this
+## #;;'
#;;# .+;;;;+,
'+;;#;,+';;;;;'#.
++'''';;;;;;;;;;# ;#;
##';;;;++'+#;;;;;'. `#:
;# '+'';;;;;;;;;'#` #.
`#, .'++;;;;;':..........#
'+ `.........';;;;':.........#
#..................+;;;;;':........#
#..................#';;;;;'+''''''.#
#.......,:;''''''''##';;;;;'+'''''#,
#''''''''''''''''''###';;;;;;+''''#
#''''''''''''''''''####';;;;;;#'''#
#''''''''''''''''''#####';;;;;;#''#
#''''''''''''''''''######';;;;;;#'#
#''''''''''''''''''#######';;;;;;##
#''''''''''''''''''########';;;;;;#
#''''''''''''++####+;#######';;;;;;#
#+####':,` ,#####';;;;;;'
+##'''''+.
___ _ ___ _ _ _
/ __\__ _| | _____ / __\_ _(_) | __| |
/ / / _` | |/ / _ \/__\// | | | | |/ _` |
/ /___ (_| | < __/ \/ \ |_| | | | (_| |
\____/\__,_|_|\_\___\_____/\__,_|_|_|\__,_|
Version 0.23.0+Branch.main.Sha.67afe72f1c21a8a3cfd96d3969fb2591d62f37ff
========================================
Install-AngularCLI
========================================
Found Angular CLI at D:/home/site/repository/tools/ng/ng.cmd.
========================================
Clean
========================================
========================================
Install
========================================
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.0.0 (node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"ia32"})
npm WARN [email protected] requires a peer of @angular/compiler@^2.3.1 || >=4.0.0-beta <5.0.0 but none was installed.
npm WARN [email protected] requires a peer of @angular/core@^2.3.1 || >=4.0.0-beta <5.0.0 but none was installed.
========================================
Build
========================================
Date: 2017-11-17T10:36:45.847Z
Hash: 3b11c732f8aa65f3a08c
Time: 8815ms
chunk {inline} inline.bundle.js, inline.bundle.js.map (inline) 5.83 kB [entry] [rendered]
chunk {main} main.bundle.js, main.bundle.js.map (main) 7.79 kB [initial] [rendered]
chunk {polyfills} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 200 kB [initial] [rendered]
chunk {styles} styles.bundle.js, styles.bundle.js.map (styles) 11.3 kB [initial] [rendered]
chunk {vendor} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.29 MB [initial] [rendered]
========================================
Publish
========================================
KuduSync.NET from: 'D:\home\site\repository\output' to: 'D:\home\site\wwwroot'
Copying file: 'favicon.ico'
Copying file: 'index.html'
Copying file: 'inline.bundle.js'
Copying file: 'inline.bundle.js.map'
Copying file: 'main.bundle.js'
Copying file: 'main.bundle.js.map'
Copying file: 'polyfills.bundle.js'
Copying file: 'polyfills.bundle.js.map'
Copying file: 'styles.bundle.js'
Copying file: 'styles.bundle.js.map'
Copying file: 'vendor.bundle.js'
Copying file: 'vendor.bundle.js.map'
Time 444
Task Duration
--------------------------------------------------
Install-AngularCLI 00:00:00.0491433
Clean 00:00:00.0782836
Install 00:00:35.4828120
Build 00:01:12.5709830
Publish 00:00:00.8032134
--------------------------------------------------
Total: 00:01:48.9844353
In the last comment you write that you want to deploy using Octopus deploy, that would basically mean adding 2 new tasks to just like the kudu publish execute post build.
For this Cake has the OctoPack and OctoPush aliases.
These aliases require the octo.exe
tool, which can be fetch using the tool
directive like this
#tool nuget:?package=OctopusTools&version=4.25.0
A pack task could look something like this
DirectoryPath nugetPath= MakeAbsolute(Directory("./nuget"));
Task("Pack")
.IsDependentOn("Build")
.Does( ()=> {
OctoPack(
"PoCApp",
new OctopusPackSettings {
BasePath = outputPath,
OutFolder = nugetPath,
Format = OctopusPackFormat.Zip
}
);
});
Once you packaged your app and pushed package to our octopus server, then you can use their built-in deploy to Azure web app functionality, there's a good guide for that at https://octopus.com/docs/deploying-applications/deploying-to-azure/deploying-a-package-to-an-azure-web-app
Some of the above code is available in the below repo https://github.com/azurevoodoo/NGAppDeployedWithKuduPoC
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With