diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..ab561f3c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/package-lock.json b/package-lock.json index e4fb69ae..ddb886eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1794,6 +1794,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -1966,6 +1967,7 @@ "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "optional": true, "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -2435,7 +2437,8 @@ "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "optional": true }, "body-parser": { "version": "1.19.0", @@ -2540,7 +2543,8 @@ "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "optional": true }, "browser-process-hrtime": { "version": "0.1.3", @@ -2569,6 +2573,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "optional": true, "requires": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -2605,6 +2610,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "optional": true, "requires": { "bn.js": "^4.1.0", "randombytes": "^2.0.1" @@ -2701,7 +2707,8 @@ "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "optional": true }, "builtin-modules": { "version": "1.1.1", @@ -2883,6 +2890,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "optional": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -3260,6 +3268,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "optional": true, "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -3272,6 +3281,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "optional": true, "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -3730,6 +3740,7 @@ "version": "6.4.1", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "optional": true, "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -3791,6 +3802,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "optional": true, "requires": { "prr": "~1.0.1" } @@ -4170,6 +4182,7 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "optional": true, "requires": { "d": "1", "es5-ext": "~0.10.14" @@ -4184,6 +4197,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "optional": true, "requires": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -4713,7 +4727,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -4731,11 +4746,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4748,15 +4765,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -4859,7 +4879,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -4869,6 +4890,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4881,17 +4903,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -4908,6 +4933,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -4980,7 +5006,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -4990,6 +5017,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -5065,7 +5093,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -5095,6 +5124,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5112,6 +5142,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5150,11 +5181,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -5462,6 +5495,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "optional": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -5471,6 +5505,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "optional": true, "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -5480,6 +5515,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "optional": true, "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -5798,7 +5834,8 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", @@ -7438,7 +7475,8 @@ "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "optional": true }, "loose-envify": { "version": "1.4.0", @@ -7529,6 +7567,7 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "optional": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -7554,6 +7593,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "optional": true, "requires": { "errno": "^0.1.3", "readable-stream": "^2.0.1" @@ -7644,12 +7684,14 @@ "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "optional": true }, "minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "optional": true }, "minimatch": { "version": "3.0.4", @@ -8247,6 +8289,7 @@ "version": "5.1.4", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", + "optional": true, "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", @@ -8355,6 +8398,7 @@ "version": "3.0.17", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "optional": true, "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -8557,7 +8601,8 @@ "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "optional": true }, "pseudomap": { "version": "1.0.2", @@ -8624,6 +8669,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "optional": true, "requires": { "safe-buffer": "^5.1.0" } @@ -9036,6 +9082,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "optional": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -9425,6 +9472,7 @@ "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "optional": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -9620,7 +9668,8 @@ "source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "optional": true }, "source-map": { "version": "0.7.3", @@ -10177,7 +10226,8 @@ "tapable": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.9.tgz", - "integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==" + "integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==", + "optional": true }, "tar-stream": { "version": "1.6.2", @@ -11027,6 +11077,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", + "optional": true, "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" @@ -11035,7 +11086,8 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true } } }, diff --git a/src/models/serverless.ts b/src/models/serverless.ts index f50d0248..bdf0dba4 100644 --- a/src/models/serverless.ts +++ b/src/models/serverless.ts @@ -1,4 +1,5 @@ import { ApiManagementConfig } from "./apiManagement"; +import Serverless from "serverless"; export interface ArmTemplateConfig { file: string; @@ -52,3 +53,7 @@ export interface ServerlessAzureConfig { plugins: string[]; functions: any; } + +export interface ServerlessAzureOptions extends Serverless.Options { + resourceGroup?: string; +} diff --git a/src/plugins/deploy/azureDeployPlugin.ts b/src/plugins/deploy/azureDeployPlugin.ts index 40362ed6..88e253cd 100644 --- a/src/plugins/deploy/azureDeployPlugin.ts +++ b/src/plugins/deploy/azureDeployPlugin.ts @@ -21,6 +21,12 @@ export class AzureDeployPlugin { "list" ] } + }, + options: { + "resourceGroup": { + usage: "Resource group for the service", + shortcut: "g", + } } } } @@ -48,12 +54,11 @@ export class AzureDeployPlugin { private async deploy() { const resourceService = new ResourceService(this.serverless, this.options); - await resourceService.deployResourceGroup(); const functionAppService = new FunctionAppService(this.serverless, this.options); - const functionApp = await functionAppService.deploy(); + await functionAppService.uploadFunctions(functionApp); } } diff --git a/src/services/armService.test.ts b/src/services/armService.test.ts index 5ff5caca..825599e0 100644 --- a/src/services/armService.test.ts +++ b/src/services/armService.test.ts @@ -2,7 +2,7 @@ import Serverless from "serverless"; import { MockFactory } from "../test/mockFactory"; import { ArmService } from "./armService"; import { ArmResourceTemplate, ArmTemplateType } from "../models/armTemplates"; -import { ArmTemplateConfig } from "../models/serverless"; +import { ArmTemplateConfig, ServerlessAzureOptions } from "../models/serverless"; import mockFs from "mock-fs"; import jsonpath from "jsonpath"; import { Deployments } from "@azure/arm-resources"; @@ -11,9 +11,10 @@ import { Deployment } from "@azure/arm-resources/esm/models"; describe("Arm Service", () => { let sls: Serverless let service: ArmService; + let options: ServerlessAzureOptions; function createService() { - return new ArmService(sls); + return new ArmService(sls, options); } beforeEach(() => { @@ -197,4 +198,4 @@ describe("Arm Service", () => { expect(call[2]).toEqual(expectedDeployment); }); }); -}); \ No newline at end of file +}); diff --git a/src/services/armService.ts b/src/services/armService.ts index 90feef5c..df1afe8f 100644 --- a/src/services/armService.ts +++ b/src/services/armService.ts @@ -3,7 +3,7 @@ import { Deployment, DeploymentExtended } from "@azure/arm-resources/esm/models" import { BaseService } from "./baseService"; import { ResourceManagementClient } from "@azure/arm-resources"; import { Guard } from "../shared/guard"; -import { ServerlessAzureConfig, ArmTemplateConfig } from "../models/serverless"; +import { ServerlessAzureConfig, ArmTemplateConfig, ServerlessAzureOptions } from "../models/serverless"; import { ArmDeployment, ArmResourceTemplateGenerator, ArmTemplateType } from "../models/armTemplates"; import fs from "fs"; import path from "path"; @@ -12,8 +12,8 @@ import jsonpath from "jsonpath"; export class ArmService extends BaseService { private resourceClient: ResourceManagementClient; - public constructor(serverless: Serverless) { - super(serverless); + public constructor(serverless: Serverless, options: ServerlessAzureOptions) { + super(serverless, options); this.resourceClient = new ResourceManagementClient(this.credentials, this.subscriptionId); } @@ -149,4 +149,4 @@ export class ArmService extends BaseService { }); } } -} \ No newline at end of file +} diff --git a/src/services/baseService.test.ts b/src/services/baseService.test.ts index 8f637e1d..06e2de23 100644 --- a/src/services/baseService.test.ts +++ b/src/services/baseService.test.ts @@ -7,9 +7,10 @@ jest.mock("request", () => MockFactory.createTestMockRequestFactory()); import request from "request"; import fs from "fs"; import { BaseService } from "./baseService"; +import { ServerlessAzureOptions } from "../models/serverless"; class MockService extends BaseService { - public constructor(serverless: Serverless, options?: Serverless.Options) { + public constructor(serverless: Serverless, options?: ServerlessAzureOptions) { super(serverless, options); } @@ -84,7 +85,7 @@ describe("Base Service", () => { it("returns region and stage based on CLI options", () => { const cliOptions = { stage: "prod", - region: "eastus2" + region: "eastus2", }; const mockService = new MockService(sls, cliOptions); @@ -92,40 +93,52 @@ describe("Base Service", () => { expect(mockService.getStage()).toEqual(cliOptions.stage); }); - it("Sets default region and stage values if not defined", () => { - const mockService = new MockService(sls); - - expect(mockService).not.toBeNull(); - expect(sls.service.provider.region).toEqual("westus"); - expect(sls.service.provider.stage).toEqual("dev"); - }); - - it("returns region and stage based on CLI options", () => { + it("use the resource group name specified in CLI", () => { + const resourceGroupName = "cliResourceGroupName" const cliOptions = { stage: "prod", - region: "eastus2" + region: "eastus2", + resourceGroup: resourceGroupName }; + const mockService = new MockService(sls, cliOptions); + const actualResourceGroupName = mockService.getResourceGroupName(); - expect(mockService.getRegion()).toEqual(cliOptions.region); - expect(mockService.getStage()).toEqual(cliOptions.stage); + expect(actualResourceGroupName).toEqual(resourceGroupName); }); - it("Generates resource group name from sls yaml config", () => { + it("use the resource group name from sls yaml config", () => { const mockService = new MockService(sls); - const resourceGroupName = mockService.getResourceGroupName(); + const actualResourceGroupName = mockService.getResourceGroupName(); - expect(resourceGroupName).toEqual(sls.service.provider["resourceGroup"]); + expect(actualResourceGroupName).toEqual(sls.service.provider["resourceGroup"]); }); it("Generates resource group from convention when NOT defined in sls yaml", () => { sls.service.provider["resourceGroup"] = null; const mockService = new MockService(sls); - const resourceGroupName = mockService.getResourceGroupName(); + const actualResourceGroupName = mockService.getResourceGroupName(); + const region = mockService.getRegion(); const stage = mockService.getStage(); + const expectedResourceGroupName = `sls-${region}-${stage}-${sls.service["service"]}-rg`; + + expect(actualResourceGroupName).toEqual(expectedResourceGroupName); + }); + + it("set default prefix when one is not defined in yaml config", () => { + const mockService = new MockService(sls); + const actualPrefix = mockService.getPrefix(); + expect(actualPrefix).toEqual("sls"); + }); + + it("use the prefix defined in sls yaml config", () => { + const expectedPrefix = "testPrefix" + sls.service.provider["prefix"] = expectedPrefix; + const mockService = new MockService(sls); + const actualPrefix = mockService.getPrefix(); - expect(resourceGroupName).toEqual(`sls-${region}-${stage}-${sls.service["service"]}-rg`); + expect(actualPrefix).toEqual(expectedPrefix); }); it("Fails if credentials have not been set in serverless config", () => { @@ -183,4 +196,4 @@ describe("Base Service", () => { readStreamSpy.mockRestore(); }); -}); \ No newline at end of file +}); diff --git a/src/services/baseService.ts b/src/services/baseService.ts index b99a5ce9..1d53d74e 100644 --- a/src/services/baseService.ts +++ b/src/services/baseService.ts @@ -2,6 +2,7 @@ import axios from "axios"; import fs from "fs"; import request from "request"; import Serverless from "serverless"; +import { ServerlessAzureOptions } from "../models/serverless"; import { StorageAccountResource } from "../armTemplates/resources/storageAccount"; import { configConstants } from "../config"; import { DeploymentConfig, ServerlessAzureConfig } from "../models/serverless"; @@ -21,11 +22,10 @@ export abstract class BaseService { protected constructor( protected serverless: Serverless, - protected options: Serverless.Options = { stage: null, region: null }, + protected options: ServerlessAzureOptions = { stage: null, region: null }, authenticate: boolean = true, ) { Guard.null(serverless); - this.setDefaultValues(); this.baseUrl = "https://management.azure.com"; @@ -44,17 +44,23 @@ export abstract class BaseService { } public getRegion(): string { - return this.options.region || this.serverless.service.provider.region; + return this.options.region || this.config.provider.region; } - + public getStage(): string { - return this.options.stage || this.serverless.service.provider.stage; + return this.options.stage || this.config.provider.stage; + } + + public getPrefix(): string { + return this.config.provider.prefix; } public getResourceGroupName(): string { - return this.options["resourceGroup"] - || this.serverless.service.provider["resourceGroup"] - || `${this.config.provider.prefix}-${this.getRegion()}-${this.getStage()}-${this.serviceName}-rg`; + const name = this.options.resourceGroup + || this.config.provider["resourceGroup"] + || `${this.getPrefix()}-${this.getRegion()}-${this.getStage()}-${this.serviceName}-rg`; + + return name; } public getDeploymentConfig(): DeploymentConfig { @@ -67,7 +73,7 @@ export abstract class BaseService { } public getDeploymentName(): string { - const name = this.serverless.service.provider["deploymentName"] || `${this.resourceGroup}-deployment` + const name = this.config.provider["deploymentName"] || `${this.resourceGroup}-deployment` return this.rollbackConfiguredName(name); } @@ -78,7 +84,7 @@ export abstract class BaseService { /** * Get the access token from credentials token cache */ - protected getAccessToken(): string{ + protected getAccessToken(): string { return (this.credentials.tokenCache as any)._entries[0].accessToken; } diff --git a/src/services/functionAppService.ts b/src/services/functionAppService.ts index ab5e69b2..c29b8da3 100644 --- a/src/services/functionAppService.ts +++ b/src/services/functionAppService.ts @@ -18,6 +18,7 @@ export class FunctionAppService extends BaseService { public constructor(serverless: Serverless, options: Serverless.Options) { super(serverless, options); + this.webClient = new WebSiteManagementClient(this.credentials, this.subscriptionId); this.blobService = new AzureBlobStorageService(serverless, options); this.functionZipFile = this.getFunctionZipFile(); @@ -114,7 +115,7 @@ export class FunctionAppService extends BaseService { public async uploadFunctions(functionApp: Site): Promise { Guard.null(functionApp, "functionApp"); - this.log("Deploying serverless functions..."); + this.log("Deploying serverless functions..."); await this.uploadZippedArfifactToFunctionApp(functionApp); await this.uploadZippedArtifactToBlobStorage(); @@ -127,14 +128,14 @@ export class FunctionAppService extends BaseService { public async deploy() { this.log(`Creating function app: ${this.serviceName}`); - const armService = new ArmService(this.serverless); + const armService = new ArmService(this.serverless, this.options); let deployment: ArmDeployment = this.config.provider.armTemplate ? await armService.createDeploymentFromConfig(this.config.provider.armTemplate) : await armService.createDeploymentFromType(this.config.provider.type || "consumption"); await armService.deployTemplate(deployment); - // Return function app + // Return function app return await this.get(); } @@ -162,7 +163,7 @@ export class FunctionAppService extends BaseService { }; await this.sendFile(requestOptions, this.functionZipFile); - + this.log("-> Function package uploaded successfully"); const serverlessFunctions = this.serverless.service.getAllFunctions(); const deployedFunctions = await this.listFunctions(functionApp); @@ -182,7 +183,7 @@ export class FunctionAppService extends BaseService { } /** - * Uploads artifact file to blob storage container + * Uploads artifact file to blob storage container */ private async uploadZippedArtifactToBlobStorage() { await this.blobService.initialize();