Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cake build angular application to deploy to azure

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.

like image 968
Akshay Bheda Avatar asked Nov 17 '17 06:11

Akshay Bheda


People also ask

Can we host Angular app in Azure?

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.

What is cake build?

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.


1 Answers

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

  1. Install Angular CLI If not found
  2. Install node modules
  3. Build Angular app

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.

  1. Package up the artifact
  2. Push to Octopus server

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

like image 138
devlead Avatar answered Sep 19 '22 17:09

devlead