Thus, creating a simple vanilla application using the Angular CLI will 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);
What basically does
- Install Angular CLI If Not Found
- Install node modules
- Build Angular Application
If you want to run the build and publish to kudu, you can use the Cake.Kudu addin and KuduSync tool, dependencies are declared by adding the tool and addin to the preprocessor as follows:
#tool nuget:?package=KuduSync.NET&version=1.3.1
And the publication task will look something like this:
Task("Publish") .IsDependentOn("Build") .Does( ()=> { Kudu.Sync(outputPath); });
For kudu, to know that it needs to use a special deployment script, you need to add a .deployment file telling it to do this, which might look something like this:
[config] command = deploy.cmd
And a custom boostrapper to install Cake I have a kudu environment, which might 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:
Which basically just clears any old versions of Cake and retrieves 0.23.0 if they are not already installed.
The full Cake script will look something like
#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 the output on the Kudu assembly running on your Azure website will 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 fsevents@1.1.3 : wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"ia32"}) npm WARN codelyzer@3.2.2 requires a peer of @angular/ compiler@ ^2.3.1 || >=4.0.0-beta <5.0.0 but none was installed. npm WARN codelyzer@3.2.2 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 deployment, which would basically mean adding 2 new tasks to somehow publish the post assembly of kudu publish.
- Artifact package
- Click on Octopus Server
There are OctoPack and OctoPush aliases for this cake.
These aliases require the octo.exe tool, which can be extracted using the tool directive, such as
A package task might 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 } ); });
After you pack your application and push the package to our octopus server, you can use their built-in deployment for the functionality of Azure web applications, there is a good guide for https://octopus.com/docs/deploying-applications/deploying-to -azure / deploying-a-package-to-an-azure-web-app
Some of the code above is available in the repo below https://github.com/azurevoodoo/NGAppDeployedWithKuduPoC