Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VSTS build - replace Angular4 environment variables in Release stage

Currently I have three different environments in Angular4:

  • Environment
  • Environment.Debug
  • Environment.Release

enter image description here

Now, in vsts build pipeline I have set up multi-configuration where one definition prepares artifacts for debug and release:
enter image description here

I am using "Replace tokens" task to replace variables per debug and release environment, before I run npm install and npm run {either debug or release) which then runs webpack to pack files for debug or release environment.

I saw there is an option to replace variables in Release where you can replace variables in your .json file(like appsettings.json): enter image description here

But problem is when webpack packs source code into one bundle.js I think I cannot use release to replace environment variables? Can I?

So what I want to achieve is decouple debug and release builds. This is simple I just recreate separate definitions for debug and release, where I am only replacing variables per environment. Second stage is to actually remove Replace tokens task from build pipeline and use Release variables section to replace variables per environment set up in Release. How is that possible for Angular after webpack builds bundle in js?

like image 828
sensei Avatar asked Apr 11 '18 09:04

sensei


People also ask

How do you use variables in a pipeline release?

You define and manage these variables in the Variables tab in a release pipeline. In the Pipeline Variables page, open the Scope drop-down list and select "Release". By default, when you add a variable, it is set to Release scope. Share values across all of the tasks within one specific stage by using stage variables.

How is the variables in variable group accessed in Azure DevOps build release definition?

To use a variable group, open your pipeline. Select Variables > Variable groups, and then choose Link variable group. In a build pipeline, you see a list of available groups. In a release pipeline, for example, you also see a drop-down list of stages in the pipeline.

How do I pass a variable from one task to another in Azure DevOps?

Share variables between Tasks across the Jobs (of the same Stage) We need to use the isOutput=true flag when you desire to use the variable in another Task located in another Job.


2 Answers

The simplest and most efficient approach is to create tokens in your Angular Environment file and use a Tokenizer in your Release to replace those tokens which got compiled in to your Main Bundle. With this approach none of your existing code has to change.

This means you will be managing your environment variables in CI/CD where they belong, instead of your project. (Your project will still need a default environment file for running locally and maybe others for local testing)

To do this, first create an Angular Environment for deployment, such as environment.deploy.ts. This is what your build will use (only one build, multiple releases).

Here is an example environment.deploy.ts:

export const environment = {
  displayLeftPanel: "__env.displayLeftPanel__".toLowerCase() === "true",
  siteName: "__env.siteName__",
  apiUrl: "__env.apiUrl__",
};

(I add env. in front of the names to ensure token names do not clash with existing names in the bundle)

In your Release Variables configure these variable for each environment:

env.displayLeftPanel
env.siteName
env.apiUrl

For your release deployment you will want task such as the below (The below is for IIS, but you can use this as a road map for anything else)

The below tasks address the following issues:

  • The build artifact is typically zipped up and we cannot tokenize inside a zip file, so we have to first unzip it.
  • The WebPack bundle names have random IDs in them (example: main.20f8aa2b341c1c2f6442.bundle.js). We need to get exact file name to pass to our Tokenizer.
  • Then we just use a Tokenizer such as the "Tokenize with XPath/Regular expressions"

Here are the tasks:

  • IIS Web App Manage
  • Extract Files: *.zip to a folder like unzipped
  • PowerShell: Get Main Bundle Name. Something like: (you may need to adjust the path)

    $MainBundleFileName = (get-item $(System.DefaultWorkingDirectory)/main.*.bundle.js).FullName; Write-Host "##vso[task.setvariable variable=MainBundleFileName;]$MainBundleFileName"

  • Tokenizer: Perform variable substitutions on the Main Bundle > $(MainBundleFileName)

  • IIS Web App Deploy: The unzipped folder
like image 98
Tolga Avatar answered Oct 25 '22 08:10

Tolga


You can get your config values out of the environment.xx.ts files and put them into json config files that you'll retrieve at runtime when angular bootstraps.

When releasing, use the token replace task you mentionned to replace the tokens in the json files.

The structure of the json file does not really matter, as long as the structure is the same for the config object client side (to make it easier to use). If the structure is not the same, you just need to transform retrieved data to assign it to your config object.

config.json

{
  "envName": "@@envName@@",
  "ApplicationInsights": { "InstrumentationKey": "@@xxx@@" }
}

Then you have a matching class in your angular app

export class MyConfig
{
  readonly envName: string;
  readonly ApplicationInsights:
  {
      readonly InstrumentationKey: string
  }

}

Once you've retrieved the json data angular side (called jsonData), assign it to a config object

config-service.ts

export let CONFIG: MyConfig;

//Modify jsonData if needed
let t = new MyConfig();
CONFIG = Object.assign(t, jsonData);

component.ts

import {CONFIG} from '../config-service.ts';
//...
//use it
let url = CONFIG.ApplicationInsights.InstrumentationKey;

Full implementation

https://stackoverflow.com/a/49559443/1160794

like image 37
David Avatar answered Oct 25 '22 07:10

David