Repository: serverless/serverless-azure-functions (ts)

Issue:
Incorrectly deploys to "West US" when provider.location specifies "West US 2"
Repro steps:
```
sls create -t azure-nodejs -p myNewApp
# Notice that the `provider.location` setting is West US 2
sls deploy
```
The region group is `sls-wus-dev-myNewApp-rg` and the region for the resources is actually `West US`
Resource group name not created with stage from CLI
Similar to #281 

Repro steps:
```
sls create -t azure-nodejs -p myNewApp
sls deploy
# Note that the resource group name is sls-wus-dev-myNewApp-rg
sls deploy --stage test
# Resource group remains the same
```
I would expect the resource group name to be sls-wus-test-myNewApp-rg

Pull request:
fix: Use stage, region, resourceGroup and prefix from CLI options
Fixes a regression in accepting `region` and `stage` options from CLI to form resource group name. Adds acceptance of `prefix` as well. Does so by configuring each of them in `serverless.service` (`ServerlessAzureConfig`) as one of the first steps of the `BaseService` constructor.

Also puts `location` into `region` inside the config if `location` is specified, but `region` is not.

Resolves #280, #282 and #281 

Patch:
diff --git a/src/models/serverless.ts b/src/models/serverless.ts
index 030fc5e..6aba1a0 100644
--- a/src/models/serverless.ts
+++ b/src/models/serverless.ts
@@ -99,6 +99,7 @@ export interface ServerlessCommandMap {
 }
 
 export interface ServerlessAzureOptions extends Serverless.Options {
+  prefix?: string;
   resourceGroup?: string;
 }
 
diff --git a/src/services/baseService.ts b/src/services/baseService.ts
index 5c3d97c..f6797e2 100644
--- a/src/services/baseService.ts
+++ b/src/services/baseService.ts
@@ -35,14 +35,14 @@ export abstract class BaseService {
   ) {
     Guard.null(serverless);
     this.setDefaultValues();
+    this.config = serverless.service as any;
+    this.setConfigFromCli();
 
     this.baseUrl = "https://management.azure.com";
     this.serviceName = this.getServiceName();
-    this.config = serverless.service as any;
     this.credentials = serverless.variables["azureCredentials"];
     this.subscriptionId = serverless.variables["subscriptionId"];
     this.resourceGroup = this.getResourceGroupName();
-    this.config.provider.resourceGroup = this.resourceGroup;
     this.deploymentConfig = this.getDeploymentConfig();
     this.deploymentName = this.getDeploymentName();
     this.artifactName = this.getArtifactName(this.deploymentName);
@@ -59,16 +59,19 @@ export abstract class BaseService {
    * Name of Azure Region for deployment
    */
   public getRegion(): string {
-    return this.options.region || this.config.provider.region;
+    return this.config.provider.region;
   }
 
   /**
    * Name of current deployment stage
    */
   public getStage(): string {
-    return this.options.stage || this.config.provider.stage;
+    return this.config.provider.stage;
   }
 
+  /**
+   * Prefix for service
+   */
   public getPrefix(): string {
     return this.config.provider.prefix;
   }
@@ -77,9 +80,7 @@ export abstract class BaseService {
    * Name of current resource group
    */
   public getResourceGroupName(): string {
-    return this.options.resourceGroup
-      || this.config.provider.resourceGroup
-      || AzureNamingService.getResourceName(this.config, null, `${this.serviceName}-rg`);
+    return this.config.provider.resourceGroup;
   }
 
   /**
@@ -243,4 +244,24 @@ export abstract class BaseService {
     }
     return timestamp;
   }
+
+  /**
+   * Overwrite values for resourceGroup, prefix, region and stage
+   * in config if passed through CLI
+   */
+  private setConfigFromCli() {
+    const { prefix, region, stage } = this.config.provider;
+    this.config.provider = {
+      ...this.config.provider,
+      prefix: this.getOption("prefix") || prefix,
+      stage: this.getOption("stage") || stage,
+      region: this.getOption("region") || region,
+    }
+    if (!this.config.provider.region && this.config.provider["location"]) {
+      this.config.provider.region = this.config.provider["location"];
+    }
+    this.config.provider.resourceGroup = (
+      this.getOption("resourceGroup", this.config.provider.resourceGroup)
+    ) || AzureNamingService.getResourceName(this.config, null, `${this.getServiceName()}-rg`);
+  }
 }
diff --git a/src/services/namingService.ts b/src/services/namingService.ts
index 86826f2..f53bf0f 100644
--- a/src/services/namingService.ts
+++ b/src/services/namingService.ts
@@ -123,13 +123,15 @@ export class AzureNamingService {
    * @param stageName The stage name
    */
   public static createShortStageName(stageName: string) {
-    Guard.empty(stageName);
+    Guard.empty(stageName, "stageName");
 
     const stageMap = {
       "dogfood": "df",
       "production": "prod",
+      "prod": "prod",
       "development": "dev",
-      "testing": "test"
+      "testing": "test",
+      "test": "test"
     };
 
     return this.createShortName(stageName, stageMap);
@@ -140,7 +142,7 @@ export class AzureNamingService {
    * @param regionName The region name
    */
   public static getNormalizedRegionName(regionName: string) {
-    Guard.empty(regionName);
+    Guard.empty(regionName, "regionName");
     return regionName.replace(/\W/g, "").toLowerCase();
   }
 
@@ -149,7 +151,7 @@ export class AzureNamingService {
    * @param regionName The azure region name
    */
   public static createShortAzureRegionName(regionName: string) {
-    Guard.empty(regionName);
+    Guard.empty(regionName, "regionName");
 
     const locationMap = {
       "north": "n",


Test patch:
diff --git a/src/services/baseService.test.ts b/src/services/baseService.test.ts
index fb7fbc7..244eb9b 100644
--- a/src/services/baseService.test.ts
+++ b/src/services/baseService.test.ts
@@ -1,7 +1,7 @@
 import fs from "fs";
 import mockFs from "mock-fs";
 import Serverless from "serverless";
-import { ServerlessAzureOptions } from "../models/serverless";
+import { ServerlessAzureOptions, ServerlessAzureConfig } from "../models/serverless";
 import { MockFactory } from "../test/mockFactory";
 import { BaseService } from "./baseService";
 import { AzureNamingService } from "./namingService";
@@ -40,9 +40,10 @@ class MockService extends BaseService {
 describe("Base Service", () => {
   let service: MockService;
   let sls: Serverless;
+  const serviceName = "my-custom-service"
 
   const slsConfig = {
-    service: "my custom service",
+    service: serviceName,
     provider: {
       resourceGroup: "My-Resource-Group",
       deploymentName: "My-Deployment",
@@ -54,7 +55,6 @@ describe("Base Service", () => {
   });
 
   function createMockService(options?: Serverless.Options) {
-    sls = MockFactory.createTestServerless();
     sls.variables["azureCredentials"] = MockFactory.createTestAzureCredentials();
     sls.variables["subscriptionId"] = "ABC123";
     Object.assign(sls.service, slsConfig);
@@ -63,6 +63,7 @@ describe("Base Service", () => {
   }
 
   beforeEach(() => {
+    sls = MockFactory.createTestServerless();
     service = createMockService();
   });
 
@@ -198,4 +199,39 @@ describe("Base Service", () => {
 
     readStreamSpy.mockRestore();
   });
+
+  it("sets stage name from CLI", async () => {
+    const stage = "test";
+    delete (sls.service as any as ServerlessAzureConfig).provider.resourceGroup;
+    expect(sls.service.provider.stage).not.toEqual(stage);
+    service = new MockService(sls, { stage } as any);
+    expect(service.getStage()).toEqual(stage);
+    expect(service.getResourceGroupName()).toEqual(`sls-wus-${stage}-${serviceName}-rg`);
+  });
+
+  it("sets region name from CLI", async () => {
+    const region = "East US";
+    delete (sls.service as any as ServerlessAzureConfig).provider.resourceGroup;
+    expect(sls.service.provider.region).not.toEqual(region);
+    service = new MockService(sls, { region } as any);
+    expect(service.getRegion()).toEqual(region);
+    expect(service.getResourceGroupName()).toEqual(`sls-eus-dev-${serviceName}-rg`);
+  });
+
+  it("sets prefix from CLI", async () => {
+    const prefix = "prefix";
+    delete (sls.service as any as ServerlessAzureConfig).provider.resourceGroup;
+    expect(sls.service.provider["prefix"]).not.toEqual(prefix);
+    service = new MockService(sls, { prefix } as any);
+    expect(service.getPrefix()).toEqual(prefix);
+    expect(service.getResourceGroupName()).toEqual(`${prefix}-wus-dev-${serviceName}-rg`);
+  });
+
+  it("sets resource group from CLI", async () => {
+    const resourceGroup = "resourceGroup";
+    delete (sls.service as any as ServerlessAzureConfig).provider.resourceGroup;
+    expect(sls.service.provider["resourceGroup"]).not.toEqual(resourceGroup);
+    service = new MockService(sls, { resourceGroup } as any);
+    expect(service.getResourceGroupName()).toEqual(resourceGroup);
+  });
 });