diff --git a/.eslintrc.json b/.eslintrc.json index 8a96041d..eb1be605 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,9 +9,6 @@ ], "@typescript-eslint/no-explicit-any": 0, "@typescript-eslint/explicit-function-return-type": 0, - "@typescript-eslint/no-parameter-properties": 0, - "@typescript-eslint/explicit-member-accessibility": 0, - "@typescript-eslint/no-var-requires": 0, - "@typescript-eslint/no-use-before-define": 0 + "@typescript-eslint/no-parameter-properties": 0 } } \ No newline at end of file diff --git a/src/config.ts b/src/config.ts index 2d8a8bf5..f2c36435 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,19 +1,19 @@ export const constants = { - bearer: 'Bearer ', - functionAppApiPath: '/api/', - functionAppDomain: '.azurewebsites.net', - functionsAdminApiPath: '/admin/functions/', - functionsApiPath: '/api/functions', - jsonContentType: 'application/json', - logInvocationsApiPath: '/azurejobs/api/functions/definitions/', - logOutputApiPath: '/azurejobs/api/log/output/', - logStreamApiPath: '/api/logstream/application/functions/function/', - masterKeyApiPath: '/api/functions/admin/masterkey', - providerName: 'azure', - scmCommandApiPath: '/api/command', - scmDomain: '.scm.azurewebsites.net', - scmVfsPath: '/api/vfs/site/wwwroot/', - scmZipDeployApiPath: '/api/zipdeploy' + bearer: "Bearer ", + functionAppApiPath: "/api/", + functionAppDomain: ".azurewebsites.net", + functionsAdminApiPath: "/admin/functions/", + functionsApiPath: "/api/functions", + jsonContentType: "application/json", + logInvocationsApiPath: "/azurejobs/api/functions/definitions/", + logOutputApiPath: "/azurejobs/api/log/output/", + logStreamApiPath: "/api/logstream/application/functions/function/", + masterKeyApiPath: "/api/functions/admin/masterkey", + providerName: "azure", + scmCommandApiPath: "/api/command", + scmDomain: ".scm.azurewebsites.net", + scmVfsPath: "/api/vfs/site/wwwroot/", + scmZipDeployApiPath: "/api/zipdeploy" }; export default constants; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 538f2c1c..1dcbbbc5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,19 +4,19 @@ This way only one plugin needs to be added to the service in order to get access whole provider implementation. */ -import Serverless from 'serverless'; -import AzureProvider from './provider/azureProvider'; -import { AzureInvoke } from './plugins/invoke/azureInvoke'; -import { AzureLogs } from './plugins/logs/azureLogs'; -import { AzureRemove } from './plugins/remove/azureRemove'; -import { AzurePackage } from './plugins/package/azurePackage'; -import { AzureDeployPlugin } from './plugins/deploy/azureDeployPlugin'; -import { AzureLoginPlugin } from './plugins/login/loginPlugin'; -import { AzureApimServicePlugin } from './plugins/apim/apimServicePlugin'; -import { AzureApimFunctionPlugin } from './plugins/apim/apimFunctionPlugin'; +import Serverless from "serverless"; +import AzureProvider from "./provider/azureProvider"; +import { AzureInvoke } from "./plugins/invoke/azureInvoke"; +import { AzureLogs } from "./plugins/logs/azureLogs"; +import { AzureRemove } from "./plugins/remove/azureRemove"; +import { AzurePackage } from "./plugins/package/azurePackage"; +import { AzureDeployPlugin } from "./plugins/deploy/azureDeployPlugin"; +import { AzureLoginPlugin } from "./plugins/login/loginPlugin"; +import { AzureApimServicePlugin } from "./plugins/apim/apimServicePlugin"; +import { AzureApimFunctionPlugin } from "./plugins/apim/apimFunctionPlugin"; export class AzureIndex { - constructor(private serverless: Serverless, private options) { + public constructor(private serverless: Serverless, private options) { this.serverless.setProvider(AzureProvider.getProviderName(), new AzureProvider(serverless) as any); // To be refactored diff --git a/src/plugins/apim/apimFunctionPlugin.test.ts b/src/plugins/apim/apimFunctionPlugin.test.ts index d7a02afd..a1c01b71 100644 --- a/src/plugins/apim/apimFunctionPlugin.test.ts +++ b/src/plugins/apim/apimFunctionPlugin.test.ts @@ -1,25 +1,25 @@ import { MockFactory } from "../../test/mockFactory"; import { invokeHook } from "../../test/utils"; -import { AzureApimFunctionPlugin } from './apimFunctionPlugin'; +import { AzureApimFunctionPlugin } from "./apimFunctionPlugin"; -jest.mock('../../services/apimService'); -import { ApimService } from '../../services/apimService'; +jest.mock("../../services/apimService"); +import { ApimService } from "../../services/apimService"; -describe('APIM Function Plugin', () => { - it('calls deploy function', async () => { +describe("APIM Function Plugin", () => { + it("calls deploy function", async () => { const deployFunction = jest.fn(); ApimService.prototype.deployFunction = deployFunction; const sls = MockFactory.createTestServerless(); - sls.service.provider['apim'] = 'apim config' + sls.service.provider["apim"] = "apim config" const options = MockFactory.createTestServerlessOptions(); const plugin = new AzureApimFunctionPlugin(sls, options); - await invokeHook(plugin, 'after:deploy:function:deploy'); + await invokeHook(plugin, "after:deploy:function:deploy"); - expect(sls.cli.log).toBeCalledWith('Starting APIM function deployment') + expect(sls.cli.log).toBeCalledWith("Starting APIM function deployment") expect(deployFunction).toBeCalled(); - expect(sls.cli.log).lastCalledWith('Finished APIM function deployment') + expect(sls.cli.log).lastCalledWith("Finished APIM function deployment") }); }); \ No newline at end of file diff --git a/src/plugins/apim/apimFunctionPlugin.ts b/src/plugins/apim/apimFunctionPlugin.ts index c4dcd6f0..8c5c9ee5 100644 --- a/src/plugins/apim/apimFunctionPlugin.ts +++ b/src/plugins/apim/apimFunctionPlugin.ts @@ -1,21 +1,21 @@ -import Serverless from 'serverless'; -import { ApimService } from '../../services/apimService'; +import Serverless from "serverless"; +import { ApimService } from "../../services/apimService"; export class AzureApimFunctionPlugin { public hooks: { [eventName: string]: Promise }; - constructor(private serverless: Serverless, private options: Serverless.Options) { + public constructor(private serverless: Serverless, private options: Serverless.Options) { this.hooks = { - 'after:deploy:function:deploy': this.deploy.bind(this) + "after:deploy:function:deploy": this.deploy.bind(this) }; } private async deploy() { - this.serverless.cli.log('Starting APIM function deployment'); + this.serverless.cli.log("Starting APIM function deployment"); const apimService = new ApimService(this.serverless, this.options); await apimService.deployFunction(this.options); - this.serverless.cli.log('Finished APIM function deployment'); + this.serverless.cli.log("Finished APIM function deployment"); } } \ No newline at end of file diff --git a/src/plugins/apim/apimServicePlugin.test.ts b/src/plugins/apim/apimServicePlugin.test.ts index c17a705d..e3434d38 100644 --- a/src/plugins/apim/apimServicePlugin.test.ts +++ b/src/plugins/apim/apimServicePlugin.test.ts @@ -1,28 +1,28 @@ -import Serverless from 'serverless'; +import Serverless from "serverless"; import { MockFactory } from "../../test/mockFactory"; import { invokeHook } from "../../test/utils"; -import { AzureApimServicePlugin } from './apimServicePlugin'; +import { AzureApimServicePlugin } from "./apimServicePlugin"; -jest.mock('../../services/apimService'); -import { ApimService } from '../../services/apimService'; +jest.mock("../../services/apimService"); +import { ApimService } from "../../services/apimService"; -describe('APIM Service Plugin', () => { - it('is defined', () => { +describe("APIM Service Plugin", () => { + it("is defined", () => { expect(AzureApimServicePlugin).toBeDefined(); }); - it('can be instantiated', () => { + it("can be instantiated", () => { const serverless = new Serverless(); const options: Serverless.Options = { - stage: '', - region: '', + stage: "", + region: "", } const plugin = new AzureApimServicePlugin(serverless, options); expect(plugin).not.toBeNull(); }); - it('calls deploy API and deploy functions', async () => { + it("calls deploy API and deploy functions", async () => { const deployApi = jest.fn(); const deployFunctions = jest.fn(); @@ -30,19 +30,19 @@ describe('APIM Service Plugin', () => { ApimService.prototype.deployFunctions = deployFunctions; const sls = MockFactory.createTestServerless(); - sls.service.provider['apim'] = 'apim config' + sls.service.provider["apim"] = "apim config" const options = MockFactory.createTestServerlessOptions(); const plugin = new AzureApimServicePlugin(sls, options); - await invokeHook(plugin, 'after:deploy:deploy'); + await invokeHook(plugin, "after:deploy:deploy"); - expect(sls.cli.log).toBeCalledWith('Starting APIM service deployment') + expect(sls.cli.log).toBeCalledWith("Starting APIM service deployment") expect(deployApi).toBeCalled(); expect(deployFunctions).toBeCalled(); - expect(sls.cli.log).lastCalledWith('Finished APIM service deployment') + expect(sls.cli.log).lastCalledWith("Finished APIM service deployment") }); - it('does not call deploy API or deploy functions when "apim" not included in config', async () => { + it("does not call deploy API or deploy functions when \"apim\" not included in config", async () => { const deployApi = jest.fn(); const deployFunctions = jest.fn(); @@ -53,7 +53,7 @@ describe('APIM Service Plugin', () => { const options = MockFactory.createTestServerlessOptions(); const plugin = new AzureApimServicePlugin(sls, options); - await invokeHook(plugin, 'after:deploy:deploy'); + await invokeHook(plugin, "after:deploy:deploy"); expect(sls.cli.log).not.toBeCalled() expect(deployApi).not.toBeCalled(); diff --git a/src/plugins/apim/apimServicePlugin.ts b/src/plugins/apim/apimServicePlugin.ts index a5255f65..2f13aef4 100644 --- a/src/plugins/apim/apimServicePlugin.ts +++ b/src/plugins/apim/apimServicePlugin.ts @@ -1,27 +1,27 @@ -import Serverless from 'serverless'; -import { ApimService } from '../../services/apimService'; +import Serverless from "serverless"; +import { ApimService } from "../../services/apimService"; export class AzureApimServicePlugin { public hooks: { [eventName: string]: Promise }; - constructor(private serverless: Serverless, private options: Serverless.Options) { + public constructor(private serverless: Serverless, private options: Serverless.Options) { this.hooks = { - 'after:deploy:deploy': this.deploy.bind(this) + "after:deploy:deploy": this.deploy.bind(this) }; } private async deploy() { - const apimConfig = this.serverless.service.provider['apim']; + const apimConfig = this.serverless.service.provider["apim"]; if (!apimConfig) { return Promise.resolve(); } - this.serverless.cli.log('Starting APIM service deployment'); + this.serverless.cli.log("Starting APIM service deployment"); const apimService = new ApimService(this.serverless, this.options); await apimService.deployApi(); await apimService.deployFunctions(); - this.serverless.cli.log('Finished APIM service deployment'); + this.serverless.cli.log("Finished APIM service deployment"); } } \ No newline at end of file diff --git a/src/plugins/deploy/azureDeployPlugin.test.ts b/src/plugins/deploy/azureDeployPlugin.test.ts index 05d3d2f5..468947dc 100644 --- a/src/plugins/deploy/azureDeployPlugin.test.ts +++ b/src/plugins/deploy/azureDeployPlugin.test.ts @@ -8,9 +8,9 @@ import { FunctionAppService } from "../../services/functionAppService"; jest.mock("../../services/resourceService"); import { ResourceService } from "../../services/resourceService"; -describe('Deploy plugin', () => { +describe("Deploy plugin", () => { - it('calls deploy hook', async () => { + it("calls deploy hook", async () => { const deployResourceGroup = jest.fn(); const functionAppStub = "Function App Stub"; const deploy = jest.fn(() => Promise.resolve(functionAppStub)); @@ -24,7 +24,7 @@ describe('Deploy plugin', () => { const options = MockFactory.createTestServerlessOptions(); const plugin = new AzureDeployPlugin(sls, options); - await invokeHook(plugin, 'deploy:deploy'); + await invokeHook(plugin, "deploy:deploy"); expect(deployResourceGroup).toBeCalled(); expect(deploy).toBeCalled(); diff --git a/src/plugins/deploy/azureDeployPlugin.ts b/src/plugins/deploy/azureDeployPlugin.ts index 56d5803a..48f09674 100644 --- a/src/plugins/deploy/azureDeployPlugin.ts +++ b/src/plugins/deploy/azureDeployPlugin.ts @@ -1,13 +1,13 @@ -import Serverless from 'serverless'; -import { ResourceService } from '../../services/resourceService'; -import { FunctionAppService } from '../../services/functionAppService'; +import Serverless from "serverless"; +import { ResourceService } from "../../services/resourceService"; +import { FunctionAppService } from "../../services/functionAppService"; export class AzureDeployPlugin { public hooks: { [eventName: string]: Promise }; - constructor(private serverless: Serverless, private options: Serverless.Options) { + public constructor(private serverless: Serverless, private options: Serverless.Options) { this.hooks = { - 'deploy:deploy': this.deploy.bind(this) + "deploy:deploy": this.deploy.bind(this) }; } diff --git a/src/plugins/invoke/azureInvoke.ts b/src/plugins/invoke/azureInvoke.ts index a672e345..f8da7e26 100644 --- a/src/plugins/invoke/azureInvoke.ts +++ b/src/plugins/invoke/azureInvoke.ts @@ -1,14 +1,14 @@ -import Serverless from 'serverless'; -import { join, isAbsolute } from 'path'; -import AzureProvider from '../../provider/azureProvider'; +import Serverless from "serverless"; +import { join, isAbsolute } from "path"; +import AzureProvider from "../../provider/azureProvider"; export class AzureInvoke { public hooks: { [eventName: string]: Promise }; private provider: AzureProvider; - constructor(private serverless: Serverless, private options: Serverless.Options) { - this.provider = (this.serverless.getProvider('azure') as any) as AzureProvider; - const path = this.options['path']; + public constructor(private serverless: Serverless, private options: Serverless.Options) { + this.provider = (this.serverless.getProvider("azure") as any) as AzureProvider; + const path = this.options["path"]; if (path) { const absolutePath = isAbsolute(path) @@ -16,26 +16,26 @@ export class AzureInvoke { : join(this.serverless.config.servicePath, path); if (!this.serverless.utils.fileExistsSync(absolutePath)) { - throw new Error('The file you provided does not exist.'); + throw new Error("The file you provided does not exist."); } - this.options['data'] = this.serverless.utils.readFileSync(absolutePath); + this.options["data"] = this.serverless.utils.readFileSync(absolutePath); } this.hooks = { - 'before:invoke:invoke': this.provider.getAdminKey.bind(this), - 'invoke:invoke': this.invoke.bind(this) + "before:invoke:invoke": this.provider.getAdminKey.bind(this), + "invoke:invoke": this.invoke.bind(this) }; } private async invoke() { const func = this.options.function; const functionObject = this.serverless.service.getFunction(func); - const eventType = Object.keys(functionObject['events'][0])[0]; + const eventType = Object.keys(functionObject["events"][0])[0]; - if (!this.options['data']) { - this.options['data'] = {}; + if (!this.options["data"]) { + this.options["data"] = {}; } - return this.provider.invoke(func, eventType, this.options['data']); + return this.provider.invoke(func, eventType, this.options["data"]); } } diff --git a/src/plugins/login/loginPlugin.test.ts b/src/plugins/login/loginPlugin.test.ts index 86f9eea4..2b31cc61 100644 --- a/src/plugins/login/loginPlugin.test.ts +++ b/src/plugins/login/loginPlugin.test.ts @@ -3,11 +3,11 @@ import { invokeHook } from "../../test/utils"; import { AzureLoginPlugin } from "./loginPlugin"; import { AzureLoginService } from "../../services/loginService"; -describe('Login Plugin', () => { +describe("Login Plugin", () => { const authResponse = MockFactory.createTestAuthResponse(); - it('returns if azure credentials are set', async () => { + it("returns if azure credentials are set", async () => { const interactiveLogin = jest.fn(() => Promise.resolve(authResponse)); const servicePrincipalLogin = jest.fn(() => Promise.resolve(authResponse)); @@ -15,17 +15,17 @@ describe('Login Plugin', () => { AzureLoginService.servicePrincipalLogin = servicePrincipalLogin; const sls = MockFactory.createTestServerless(); - sls.variables['azureCredentials'] = 'credentials'; + sls.variables["azureCredentials"] = "credentials"; const options = MockFactory.createTestServerlessOptions(); const plugin = new AzureLoginPlugin(sls, options); - await invokeHook(plugin, 'before:package:initialize'); + await invokeHook(plugin, "before:package:initialize"); expect(interactiveLogin).not.toBeCalled(); expect(servicePrincipalLogin).not.toBeCalled(); }); - it('calls login if azure credentials are not set', async () => { + it("calls login if azure credentials are not set", async () => { const interactiveLogin = jest.fn(() => Promise.resolve(authResponse)); const servicePrincipalLogin = jest.fn(() => Promise.resolve(authResponse)); @@ -36,18 +36,18 @@ describe('Login Plugin', () => { const options = MockFactory.createTestServerlessOptions(); const plugin = new AzureLoginPlugin(sls, options); - await invokeHook(plugin, 'before:package:initialize'); + await invokeHook(plugin, "before:package:initialize"); expect(interactiveLogin).toBeCalled(); expect(servicePrincipalLogin).not.toBeCalled(); }); - it('calls service principal login if environment variables are set', async () => { + it("calls service principal login if environment variables are set", async () => { - process.env.azureSubId = 'azureSubId'; - process.env.azureServicePrincipalClientId = 'azureServicePrincipalClientId'; - process.env.azureServicePrincipalPassword = 'azureServicePrincipalPassword'; - process.env.azureServicePrincipalTenantId = 'azureServicePrincipalTenantId'; + process.env.azureSubId = "azureSubId"; + process.env.azureServicePrincipalClientId = "azureServicePrincipalClientId"; + process.env.azureServicePrincipalPassword = "azureServicePrincipalPassword"; + process.env.azureServicePrincipalTenantId = "azureServicePrincipalTenantId"; const interactiveLogin = jest.fn(() => Promise.resolve(authResponse)); const servicePrincipalLogin = jest.fn(() => Promise.resolve(authResponse)); @@ -58,19 +58,19 @@ describe('Login Plugin', () => { const sls = MockFactory.createTestServerless(); const options = MockFactory.createTestServerlessOptions(); const plugin = new AzureLoginPlugin(sls, options); - await invokeHook(plugin, 'before:package:initialize'); + await invokeHook(plugin, "before:package:initialize"); expect(servicePrincipalLogin).toBeCalledWith( - 'azureServicePrincipalClientId', - 'azureServicePrincipalPassword', - 'azureServicePrincipalTenantId' + "azureServicePrincipalClientId", + "azureServicePrincipalPassword", + "azureServicePrincipalTenantId" ) expect(interactiveLogin).not.toBeCalled(); - expect(sls.variables['azureCredentials']).toEqual(authResponse.credentials); - expect(sls.variables['subscriptionId']).toEqual('azureSubId'); + expect(sls.variables["azureCredentials"]).toEqual(authResponse.credentials); + expect(sls.variables["subscriptionId"]).toEqual("azureSubId"); }); - it('calls interactive login if environment variables are not set', async () => { + it("calls interactive login if environment variables are not set", async () => { delete process.env.azureSubId; delete process.env.azureServicePrincipalClientId; delete process.env.azureServicePrincipalPassword; @@ -85,22 +85,22 @@ describe('Login Plugin', () => { const sls = MockFactory.createTestServerless(); const options = MockFactory.createTestServerlessOptions(); const plugin = new AzureLoginPlugin(sls, options); - await invokeHook(plugin, 'before:package:initialize'); + await invokeHook(plugin, "before:package:initialize"); expect(servicePrincipalLogin).not.toBeCalled(); expect(interactiveLogin).toBeCalled(); - expect(sls.variables['azureCredentials']).toEqual(authResponse.credentials); - expect(sls.variables['subscriptionId']).toEqual('azureSubId'); + expect(sls.variables["azureCredentials"]).toEqual(authResponse.credentials); + expect(sls.variables["subscriptionId"]).toEqual("azureSubId"); }); - it('logs an error from authentication', async () => { - process.env.azureSubId = 'azureSubId'; - process.env.azureServicePrincipalClientId = 'azureServicePrincipalClientId'; - process.env.azureServicePrincipalPassword = 'azureServicePrincipalPassword'; - process.env.azureServicePrincipalTenantId = 'azureServicePrincipalTenantId'; + it("logs an error from authentication", async () => { + process.env.azureSubId = "azureSubId"; + process.env.azureServicePrincipalClientId = "azureServicePrincipalClientId"; + process.env.azureServicePrincipalPassword = "azureServicePrincipalPassword"; + process.env.azureServicePrincipalTenantId = "azureServicePrincipalTenantId"; const interactiveLogin = jest.fn(() => Promise.resolve(authResponse)); - const errorMessage = 'This is my error message'; + const errorMessage = "This is my error message"; const servicePrincipalLogin = jest.fn(() => { throw new Error(errorMessage); }); @@ -111,11 +111,11 @@ describe('Login Plugin', () => { const sls = MockFactory.createTestServerless(); const options = MockFactory.createTestServerlessOptions(); const plugin = new AzureLoginPlugin(sls, options); - await invokeHook(plugin, 'before:package:initialize'); + await invokeHook(plugin, "before:package:initialize"); expect(servicePrincipalLogin).toBeCalledWith( - 'azureServicePrincipalClientId', - 'azureServicePrincipalPassword', - 'azureServicePrincipalTenantId' + "azureServicePrincipalClientId", + "azureServicePrincipalPassword", + "azureServicePrincipalTenantId" ) expect(interactiveLogin).not.toBeCalled(); expect(sls.cli.log).lastCalledWith(`Error: ${errorMessage}`) diff --git a/src/plugins/login/loginPlugin.ts b/src/plugins/login/loginPlugin.ts index 75072d35..d64635e6 100644 --- a/src/plugins/login/loginPlugin.ts +++ b/src/plugins/login/loginPlugin.ts @@ -1,36 +1,36 @@ -import Serverless from 'serverless'; -import AzureProvider from '../../provider/azureProvider'; -import { AzureLoginService } from '../../services/loginService'; +import Serverless from "serverless"; +import AzureProvider from "../../provider/azureProvider"; +import { AzureLoginService } from "../../services/loginService"; export class AzureLoginPlugin { private provider: AzureProvider; public hooks: { [eventName: string]: Promise }; - constructor(private serverless: Serverless, private options: Serverless.Options) { - this.provider = (this.serverless.getProvider('azure') as any) as AzureProvider; + public constructor(private serverless: Serverless, private options: Serverless.Options) { + this.provider = (this.serverless.getProvider("azure") as any) as AzureProvider; this.hooks = { - 'before:package:initialize': this.login.bind(this) + "before:package:initialize": this.login.bind(this) }; } private async login() { // If credentials have already been set then short circuit - if (this.serverless.variables['azureCredentials']) { + if (this.serverless.variables["azureCredentials"]) { return; } - this.serverless.cli.log('Logging into Azure'); + this.serverless.cli.log("Logging into Azure"); try { const authResult = await AzureLoginService.login(); - this.serverless.variables['azureCredentials'] = authResult.credentials; + this.serverless.variables["azureCredentials"] = authResult.credentials; // Use environment variable for sub ID or use the first subscription in the list (service principal can // have access to more than one subscription) - this.serverless.variables['subscriptionId'] = process.env.azureSubId || authResult.subscriptions[0].id; + this.serverless.variables["subscriptionId"] = process.env.azureSubId || authResult.subscriptions[0].id; } catch (e) { - this.serverless.cli.log('Error logging into azure'); + this.serverless.cli.log("Error logging into azure"); this.serverless.cli.log(`${e}`); } } diff --git a/src/plugins/logs/azureLogs.ts b/src/plugins/logs/azureLogs.ts index 86c522ec..1a50f074 100644 --- a/src/plugins/logs/azureLogs.ts +++ b/src/plugins/logs/azureLogs.ts @@ -1,16 +1,16 @@ -import Serverless from 'serverless'; -import AzureProvider from '../../provider/azureProvider'; +import Serverless from "serverless"; +import AzureProvider from "../../provider/azureProvider"; export class AzureLogs { public hooks: { [eventName: string]: Promise }; private provider: AzureProvider; - constructor(private serverless: Serverless, private options: Serverless.Options) { - this.provider = (this.serverless.getProvider('azure') as any) as AzureProvider; + public constructor(private serverless: Serverless, private options: Serverless.Options) { + this.provider = (this.serverless.getProvider("azure") as any) as AzureProvider; this.hooks = { - 'logs:logs': this.retrieveLogs.bind(this) + "logs:logs": this.retrieveLogs.bind(this) }; } diff --git a/src/plugins/package/azurePackage.test.ts b/src/plugins/package/azurePackage.test.ts index 1c18d650..bf8acca2 100644 --- a/src/plugins/package/azurePackage.test.ts +++ b/src/plugins/package/azurePackage.test.ts @@ -2,15 +2,15 @@ import { MockFactory } from "../../test/mockFactory"; import { invokeHook } from "../../test/utils"; import { AzurePackage } from "./azurePackage" -jest.mock('../../shared/bindings'); -import { BindingUtils } from '../../shared/bindings'; -jest.mock('../../shared/utils'); -import { Utils, FunctionMetadata } from '../../shared/utils'; +jest.mock("../../shared/bindings"); +import { BindingUtils } from "../../shared/bindings"; +jest.mock("../../shared/utils"); +import { Utils, FunctionMetadata } from "../../shared/utils"; -describe('Azure Package Plugin', () => { - it('sets up provider configuration', async () => { - const metadata = 'metadata'; - const functionName = 'function1'; +describe("Azure Package Plugin", () => { + it("sets up provider configuration", async () => { + const metadata = "metadata"; + const functionName = "function1"; const getFunctionMetaDataFn = jest.fn(() => metadata as any as FunctionMetadata); const createEventsBindingsFn = jest.fn(); @@ -22,9 +22,9 @@ describe('Azure Package Plugin', () => { const options = MockFactory.createTestServerlessOptions(); const plugin = new AzurePackage(sls, options); - await invokeHook(plugin, 'package:setupProviderConfiguration'); + await invokeHook(plugin, "package:setupProviderConfiguration"); - expect(sls.cli.log).toBeCalledWith('Building Azure Events Hooks'); + expect(sls.cli.log).toBeCalledWith("Building Azure Events Hooks"); expect(getFunctionMetaDataFn).toBeCalledWith(functionName, sls); expect(createEventsBindingsFn).toBeCalledWith(sls.config.servicePath, functionName, metadata); }); diff --git a/src/plugins/package/azurePackage.ts b/src/plugins/package/azurePackage.ts index 1eb4446f..903effad 100644 --- a/src/plugins/package/azurePackage.ts +++ b/src/plugins/package/azurePackage.ts @@ -1,21 +1,21 @@ -import Serverless from 'serverless'; -import AzureProvider from '../../provider/azureProvider'; -import { BindingUtils } from '../../shared/bindings'; -import { Utils } from '../../shared/utils'; +import Serverless from "serverless"; +import AzureProvider from "../../provider/azureProvider"; +import { BindingUtils } from "../../shared/bindings"; +import { Utils } from "../../shared/utils"; export class AzurePackage { - provider: AzureProvider + public provider: AzureProvider public hooks: { [eventName: string]: Promise }; - constructor(private serverless: Serverless, private options: Serverless.Options) { + public constructor(private serverless: Serverless, private options: Serverless.Options) { this.hooks = { - 'package:setupProviderConfiguration': this.setupProviderConfiguration.bind(this), + "package:setupProviderConfiguration": this.setupProviderConfiguration.bind(this), }; } private async setupProviderConfiguration() { - this.serverless.cli.log('Building Azure Events Hooks'); + this.serverless.cli.log("Building Azure Events Hooks"); const createEventsPromises = this.serverless.service.getAllFunctions() .map((functionName) => { diff --git a/src/plugins/remove/azureRemove.test.ts b/src/plugins/remove/azureRemove.test.ts index 223531f8..23d5eb31 100644 --- a/src/plugins/remove/azureRemove.test.ts +++ b/src/plugins/remove/azureRemove.test.ts @@ -5,8 +5,8 @@ import { AzureRemove } from "./azureRemove"; jest.mock("../../services/resourceService"); import { ResourceService } from "../../services/resourceService"; -describe('Remove Plugin', () => { - it('calls remove hook', async () => { +describe("Remove Plugin", () => { + it("calls remove hook", async () => { const deleteDeployment = jest.fn(); const deleteResourceGroup = jest.fn(); @@ -17,10 +17,10 @@ describe('Remove Plugin', () => { const options = MockFactory.createTestServerlessOptions(); const plugin = new AzureRemove(sls, options); - await invokeHook(plugin, 'remove:remove'); + await invokeHook(plugin, "remove:remove"); expect(deleteDeployment).toBeCalled(); expect(deleteResourceGroup).toBeCalled(); - expect(sls.cli.log).toBeCalledWith('Service successfully removed'); + expect(sls.cli.log).toBeCalledWith("Service successfully removed"); }); }); \ No newline at end of file diff --git a/src/plugins/remove/azureRemove.ts b/src/plugins/remove/azureRemove.ts index f9bf78d6..0ad85b22 100644 --- a/src/plugins/remove/azureRemove.ts +++ b/src/plugins/remove/azureRemove.ts @@ -1,12 +1,12 @@ -import Serverless from 'serverless'; -import { ResourceService } from '../../services/resourceService'; +import Serverless from "serverless"; +import { ResourceService } from "../../services/resourceService"; export class AzureRemove { public hooks: { [eventName: string]: Promise }; - constructor(private serverless: Serverless, private options: Serverless.Options) { + public constructor(private serverless: Serverless, private options: Serverless.Options) { this.hooks = { - 'remove:remove': this.remove.bind(this) + "remove:remove": this.remove.bind(this) }; } @@ -15,6 +15,6 @@ export class AzureRemove { await resourceClient.deleteDeployment(); await resourceClient.deleteResourceGroup(); - this.serverless.cli.log('Service successfully removed'); + this.serverless.cli.log("Service successfully removed"); } } diff --git a/src/provider/azureProvider.ts b/src/provider/azureProvider.ts index a3d752a3..3d31d02b 100644 --- a/src/provider/azureProvider.ts +++ b/src/provider/azureProvider.ts @@ -1,8 +1,8 @@ -import fs from 'fs'; -import { join } from 'path'; -import request from 'request'; -import Serverless from 'serverless'; -import config from '../config'; +import fs from "fs"; +import { join } from "path"; +import request from "request"; +import Serverless from "serverless"; +import config from "../config"; let functionAppName; let functionsAdminKey; @@ -12,16 +12,16 @@ export default class AzureProvider { public credentials: any; private serverless: any; - static getProviderName() { + public static getProviderName() { return config.providerName; } - constructor(serverless: Serverless) { + public constructor(serverless: Serverless) { this.serverless = serverless; this.serverless.setProvider(config.providerName, this); } - getAdminKey(): Promise { + public getAdminKey(): Promise { const options = { url: `https://${functionAppName}${config.scmDomain}${config.masterKeyApiPath}`, json: true, @@ -42,21 +42,21 @@ export default class AzureProvider { }); } - pingHostStatus(functionName): Promise { + public pingHostStatus(functionName): Promise { const requestUrl = `https://${functionAppName}${config.functionAppDomain}/admin/functions/${functionName}/status`; const options = { host: functionAppName + config.functionAppDomain, - method: 'get', + method: "get", url: requestUrl, json: true, headers: { - 'x-functions-key': functionsAdminKey, - Accept: 'application/json,*/*' + "x-functions-key": functionsAdminKey, + Accept: "application/json,*/*" } }; return new Promise((resolve, reject) => { - this.serverless.cli.log('Pinging host status...'); + this.serverless.cli.log("Pinging host status..."); request(options, (err, res, body) => { if (err) return reject(err); if (body && body.Error) return reject(body.Error); @@ -70,28 +70,28 @@ export default class AzureProvider { }); } - getLogsStream(functionName) { + public getLogsStream(functionName) { const logOptions = { url: `https://${functionAppName}${config.scmDomain}${config.logStreamApiPath}${functionName}`, headers: { Authorization: config.bearer + this.credentials.tokenCache._entries[0].accessToken, - Accept: '*/*' + Accept: "*/*" } }; request .get(logOptions) - .on('error', () => { - console.error('Disconnected from log streaming.'); + .on("error", () => { + console.error("Disconnected from log streaming."); }) - .on('end', () => this.getLogsStream(functionName)) + .on("end", () => this.getLogsStream(functionName)) .pipe(process.stdout); } - getInvocationId(functionName): Promise { + public getInvocationId(functionName): Promise { const options = { url: `https://${functionAppName}${config.scmDomain}${config.logInvocationsApiPath + functionAppName}-${functionName}/invocations?limit=5`, - method: 'GET', + method: "GET", json: true, headers: { Authorization: config.bearer + this.credentials.tokenCache._entries[0].accessToken @@ -110,11 +110,11 @@ export default class AzureProvider { }); } - getLogsForInvocationId(): Promise { + public getLogsForInvocationId(): Promise { this.serverless.cli.log(`Logs for InvocationId: ${invocationId}`); const options = { url: `https://${functionAppName}${config.scmDomain}${config.logOutputApiPath}${invocationId}`, - method: 'GET', + method: "GET", json: true, headers: { Authorization: config.bearer + this.credentials.tokenCache._entries[0].accessToken @@ -131,33 +131,33 @@ export default class AzureProvider { }); } - invoke(functionName, eventType, eventData): Promise { - if (eventType === 'http') { - let queryString = ''; + public invoke(functionName, eventType, eventData): Promise { + if (eventType === "http") { + let queryString = ""; if (eventData) { - if (typeof eventData === 'string') { + if (typeof eventData === "string") { try { eventData = JSON.parse(eventData); } catch (error) { - return Promise.reject('The specified input data isn\'t a valid JSON string. ' + - 'Please correct it and try invoking the function again.'); + return Promise.reject("The specified input data isn't a valid JSON string. " + + "Please correct it and try invoking the function again."); } } queryString = Object.keys(eventData) .map((key) => `${key}=${eventData[key]}`) - .join('&'); + .join("&"); } return new Promise((resolve, reject) => { const options = { headers: { - 'x-functions-key': functionsAdminKey + "x-functions-key": functionsAdminKey }, url: `http://${functionAppName}${config.functionAppDomain}${config.functionAppApiPath + functionName}?${queryString}`, - method: 'GET', + method: "GET", json: true, }; @@ -177,13 +177,13 @@ export default class AzureProvider { const options = { host: config.functionAppDomain, - method: 'post', + method: "post", body: eventData, url: requestUrl, json: true, headers: { - 'x-functions-key': functionsAdminKey, - Accept: 'application/json,*/*' + "x-functions-key": functionsAdminKey, + Accept: "application/json,*/*" } }; @@ -198,19 +198,19 @@ export default class AzureProvider { }); } - uploadPackageJson(): Promise { - const packageJsonFilePath = join(this.serverless.config.servicePath, 'package.json'); - this.serverless.cli.log('Uploading package.json...'); + public uploadPackageJson(): Promise { + const packageJsonFilePath = join(this.serverless.config.servicePath, "package.json"); + this.serverless.cli.log("Uploading package.json..."); const requestUrl = `https://${functionAppName}${config.scmDomain}${config.scmVfsPath}package.json`; const options = { host: functionAppName + config.scmDomain, - method: 'put', + method: "put", url: requestUrl, json: true, headers: { Authorization: config.bearer + this.credentials.tokenCache._entries[0].accessToken, - Accept: '*/*' + Accept: "*/*" } }; @@ -221,12 +221,12 @@ export default class AzureProvider { if (err) { reject(err); } else { - resolve('Package.json file uploaded'); + resolve("Package.json file uploaded"); } })); } else { - resolve('Package.json file does not exist'); + resolve("Package.json file does not exist"); } }); } diff --git a/src/services/apimService.ts b/src/services/apimService.ts index 1e0bc364..7516cf34 100644 --- a/src/services/apimService.ts +++ b/src/services/apimService.ts @@ -1,7 +1,7 @@ -import Serverless from 'serverless'; -import { ApiManagementClient } from '@azure/arm-apimanagement'; -import { FunctionAppService } from './functionAppService'; -import { BaseService } from './baseService'; +import Serverless from "serverless"; +import { ApiManagementClient } from "@azure/arm-apimanagement"; +import { FunctionAppService } from "./functionAppService"; +import { BaseService } from "./baseService"; /** * APIM Service handles deployment and integration with Azure API Management @@ -11,10 +11,10 @@ export class ApimService extends BaseService { private functionAppService: FunctionAppService; private config: any; - constructor(serverless: Serverless, options: Serverless.Options) { + public constructor(serverless: Serverless, options: Serverless.Options) { super(serverless, options); - this.config = this.serverless.service.provider['apim']; + this.config = this.serverless.service.provider["apim"]; this.apimClient = new ApiManagementClient(this.credentials, this.subscriptionId); this.functionAppService = new FunctionAppService(serverless, options); } @@ -34,7 +34,7 @@ export class ApimService extends BaseService { * Deploys all the functions of the serverless service to APIM */ public async deployFunctions() { - this.serverless.cli.log('-> Deploying API Operations'); + this.serverless.cli.log("-> Deploying API Operations"); const deployApiTasks = this.serverless.service .getAllFunctions() @@ -48,7 +48,7 @@ export class ApimService extends BaseService { * @param options */ public async deployFunction(options) { - const functionConfig = this.serverless.service['functions'][options.function]; + const functionConfig = this.serverless.service["functions"][options.function]; if (!functionConfig.apim) { return; @@ -68,7 +68,7 @@ export class ApimService extends BaseService { * Deploys the APIM API referenced by the serverless service */ private async ensureApi() { - this.serverless.cli.log('-> Deploying API') + this.serverless.cli.log("-> Deploying API") try { await this.apimClient.api.createOrUpdate(this.resourceGroup, this.config.resourceId, this.config.name, { @@ -81,7 +81,7 @@ export class ApimService extends BaseService { ] }); } catch (e) { - this.serverless.cli.log('Error creating APIM API'); + this.serverless.cli.log("Error creating APIM API"); this.serverless.cli.log(JSON.stringify(e.body, null, 4)); } } @@ -91,23 +91,23 @@ export class ApimService extends BaseService { * @param functionAppUrl The host name for the deployed function app */ private async ensureBackend(functionApp) { - this.serverless.cli.log('-> Deploying API Backend') + this.serverless.cli.log("-> Deploying API Backend") try { const functionAppResourceId = `https://management.azure.com${functionApp.id}`; await this.apimClient.backend.createOrUpdate(this.resourceGroup, this.config.resourceId, this.serviceName, { credentials: { header: { - 'x-functions-key': [`{{${this.serviceName}-key}}`], + "x-functions-key": [`{{${this.serviceName}-key}}`], } }, description: this.serviceName, - protocol: 'http', + protocol: "http", resourceId: functionAppResourceId, url: `https://${functionApp.defaultHostName}/api` }); } catch (e) { - this.serverless.cli.log('Error creating APIM Backend'); + this.serverless.cli.log("Error creating APIM Backend"); this.serverless.cli.log(JSON.stringify(e.body, null, 4)); } } @@ -125,7 +125,7 @@ export class ApimService extends BaseService { const operationConfig = { displayName: options.operation.displayName || options.function, - description: options.operation.description || '', + description: options.operation.description || "", urlTemplate: options.operation.path, method: options.operation.method, templateParameters: options.operation.templateParameters || [], @@ -134,7 +134,7 @@ export class ApimService extends BaseService { await client.apiOperation.createOrUpdate(this.resourceGroup, this.config.resourceId, this.config.name, options.function, operationConfig); await client.apiOperationPolicy.createOrUpdate(this.resourceGroup, this.config.resourceId, this.config.name, options.function, { - format: 'rawxml', + format: "rawxml", value: ` @@ -163,7 +163,7 @@ export class ApimService extends BaseService { * @param functionAppUrl The host name for the Azure function app */ private async ensureFunctionAppKeys(functionApp) { - this.serverless.cli.log('-> Deploying API keys') + this.serverless.cli.log("-> Deploying API keys") try { const masterKey = await this.functionAppService.getMasterKey(functionApp); const keyName = `${this.serviceName}-key`; @@ -174,7 +174,7 @@ export class ApimService extends BaseService { value: masterKey }); } catch (e) { - this.serverless.cli.log('Error creating APIM Property'); + this.serverless.cli.log("Error creating APIM Property"); this.serverless.cli.log(JSON.stringify(e, null, 4)); } } diff --git a/src/services/baseService.ts b/src/services/baseService.ts index cb7d9761..b920b6d6 100644 --- a/src/services/baseService.ts +++ b/src/services/baseService.ts @@ -1,7 +1,7 @@ -import Serverless from 'serverless'; -import axios from 'axios'; -import request from 'request' -import fs from 'fs'; +import Serverless from "serverless"; +import axios from "axios"; +import request from "request" +import fs from "fs"; export abstract class BaseService { protected baseUrl: string; @@ -11,22 +11,22 @@ export abstract class BaseService { protected resourceGroup: string; protected deploymentName: string; - constructor(protected serverless: Serverless, protected options: Serverless.Options) { - this.baseUrl = 'https://management.azure.com'; - this.serviceName = serverless.service['service']; - this.credentials = serverless.variables['azureCredentials']; - this.subscriptionId = serverless.variables['subscriptionId']; - this.resourceGroup = serverless.service.provider['resourceGroup'] || `${this.serviceName}-rg`; - this.deploymentName = serverless.service.provider['deploymentName'] || `${this.resourceGroup}-deployment`; + public constructor(protected serverless: Serverless, protected options: Serverless.Options) { + this.baseUrl = "https://management.azure.com"; + this.serviceName = serverless.service["service"]; + this.credentials = serverless.variables["azureCredentials"]; + this.subscriptionId = serverless.variables["subscriptionId"]; + this.resourceGroup = serverless.service.provider["resourceGroup"] || `${this.serviceName}-rg`; + this.deploymentName = serverless.service.provider["deploymentName"] || `${this.resourceGroup}-deployment`; if (!this.credentials) { throw new Error(`Azure Credentials has not been set in ${this.constructor.name}`); } } - async sendApiRequest(method: string, relativeUrl: string, options: any = {}) { + protected async sendApiRequest(method: string, relativeUrl: string, options: any = {}) { const defaultHeaders = { - 'Authorization': `Bearer ${this.credentials.tokenCache._entries[0].accessToken}` + "Authorization": `Bearer ${this.credentials.tokenCache._entries[0].accessToken}` }; const allHeaders = { @@ -53,7 +53,7 @@ export abstract class BaseService { const id = setInterval(async () => { if (retries >= 20) { clearInterval(id); - return reject('Failed conditional check 20 times'); + return reject("Failed conditional check 20 times"); } retries++; diff --git a/src/services/functionAppService.ts b/src/services/functionAppService.ts index f40e6204..ef02e69e 100644 --- a/src/services/functionAppService.ts +++ b/src/services/functionAppService.ts @@ -1,19 +1,19 @@ -import fs from 'fs'; -import path from 'path'; -import { WebSiteManagementClient } from '@azure/arm-appservice'; -import { ResourceManagementClient } from '@azure/arm-resources'; -import { Deployment } from '@azure/arm-resources/esm/models'; -import jsonpath from 'jsonpath'; -import _ from 'lodash'; -import Serverless from 'serverless'; -import { BaseService } from './baseService'; -import { constants } from '../config'; +import fs from "fs"; +import path from "path"; +import { WebSiteManagementClient } from "@azure/arm-appservice"; +import { ResourceManagementClient } from "@azure/arm-resources"; +import { Deployment } from "@azure/arm-resources/esm/models"; +import jsonpath from "jsonpath"; +import _ from "lodash"; +import Serverless from "serverless"; +import { BaseService } from "./baseService"; +import { constants } from "../config"; export class FunctionAppService extends BaseService { private resourceClient: ResourceManagementClient; private webClient: WebSiteManagementClient; - constructor(serverless: Serverless, options: Serverless.Options) { + public constructor(serverless: Serverless, options: Serverless.Options) { super(serverless, options); this.resourceClient = new ResourceManagementClient(this.credentials, this.subscriptionId); @@ -22,7 +22,7 @@ export class FunctionAppService extends BaseService { public async get() { const response: any = await this.webClient.webApps.get(this.resourceGroup, this.serviceName); - if (response.error && (response.error.code === 'ResourceNotFound' || response.error.code === 'ResourceGroupNotFound')) { + if (response.error && (response.error.code === "ResourceNotFound" || response.error.code === "ResourceGroupNotFound")) { return null; } @@ -34,10 +34,10 @@ export class FunctionAppService extends BaseService { const adminToken = await this.getAuthKey(functionApp); const keyUrl = `https://${functionApp.defaultHostName}/admin/host/systemkeys/_master`; - const response = await this.sendApiRequest('GET', keyUrl, { + const response = await this.sendApiRequest("GET", keyUrl, { json: true, headers: { - 'Authorization': `Bearer ${adminToken}` + "Authorization": `Bearer ${adminToken}` } }); @@ -50,14 +50,14 @@ export class FunctionAppService extends BaseService { } public async syncTriggers(functionApp) { - this.serverless.cli.log('Syncing function triggers'); + this.serverless.cli.log("Syncing function triggers"); const syncTriggersUrl = `${this.baseUrl}${functionApp.id}/syncfunctiontriggers?api-version=2016-08-01`; - await this.sendApiRequest('POST', syncTriggersUrl); + await this.sendApiRequest("POST", syncTriggersUrl); } public async cleanUp(functionApp) { - this.serverless.cli.log('Cleaning up existing functions'); + this.serverless.cli.log("Cleaning up existing functions"); const deleteTasks = []; const serviceFunctions = this.serverless.service.getAllFunctions(); @@ -75,7 +75,7 @@ export class FunctionAppService extends BaseService { public async listFunctions(functionApp) { const getTokenUrl = `${this.baseUrl}${functionApp.id}/functions?api-version=2016-08-01`; - const response = await this.sendApiRequest('GET', getTokenUrl); + const response = await this.sendApiRequest("GET", getTokenUrl); return response.data.value || []; } @@ -89,9 +89,9 @@ export class FunctionAppService extends BaseService { this.serverless.cli.log(`Deploying zip file to function app: ${functionAppName}`); // Upload function artifact if it exists, otherwise the full service is handled in 'uploadFunctions' method - const functionZipFile = this.serverless.service['artifact']; + const functionZipFile = this.serverless.service["artifact"]; if (!functionZipFile) { - throw new Error('No zip file found for function app'); + throw new Error("No zip file found for function app"); } this.serverless.cli.log(`-> Uploading ${functionZipFile}`); @@ -101,19 +101,19 @@ export class FunctionAppService extends BaseService { // https://github.com/projectkudu/kudu/wiki/Deploying-from-a-zip-file-or-url const requestOptions = { - method: 'POST', + method: "POST", uri: uploadUrl, json: true, headers: { Authorization: `Bearer ${this.credentials.tokenCache._entries[0].accessToken}`, - Accept: '*/*', - ContentType: 'application/octet-stream', + Accept: "*/*", + ContentType: "application/octet-stream", } }; try { await this.sendFile(requestOptions, functionZipFile); - this.serverless.cli.log('-> Function package uploaded successfully'); + this.serverless.cli.log("-> Function package uploaded successfully"); } catch (e) { throw new Error(`Error uploading zip file:\n --> ${e}`); } @@ -127,7 +127,7 @@ export class FunctionAppService extends BaseService { this.serverless.cli.log(`Creating function app: ${this.serviceName}`); let parameters: any = { functionAppName: { value: this.serviceName } }; - const gitUrl = this.serverless.service.provider['gitUrl']; + const gitUrl = this.serverless.service.provider["gitUrl"]; if (gitUrl) { parameters = { @@ -136,33 +136,33 @@ export class FunctionAppService extends BaseService { }; } - let templateFilePath = path.join(__dirname, '..', 'provider', 'armTemplates', 'azuredeploy.json'); + let templateFilePath = path.join(__dirname, "..", "provider", "armTemplates", "azuredeploy.json"); if (gitUrl) { - templateFilePath = path.join(__dirname, 'armTemplates', 'azuredeployWithGit.json'); + templateFilePath = path.join(__dirname, "armTemplates", "azuredeployWithGit.json"); } - if (this.serverless.service.provider['armTemplate']) { - this.serverless.cli.log(`-> Deploying custom ARM template: ${this.serverless.service.provider['armTemplate'].file}`); - templateFilePath = path.join(this.serverless.config.servicePath, this.serverless.service.provider['armTemplate'].file); - const userParameters = this.serverless.service.provider['armTemplate'].parameters; + if (this.serverless.service.provider["armTemplate"]) { + this.serverless.cli.log(`-> Deploying custom ARM template: ${this.serverless.service.provider["armTemplate"].file}`); + templateFilePath = path.join(this.serverless.config.servicePath, this.serverless.service.provider["armTemplate"].file); + const userParameters = this.serverless.service.provider["armTemplate"].parameters; const userParametersKeys = Object.keys(userParameters); for (let paramIndex = 0; paramIndex < userParametersKeys.length; paramIndex++) { const item = {}; - item[userParametersKeys[paramIndex]] = { 'value': userParameters[userParametersKeys[paramIndex]] }; + item[userParametersKeys[paramIndex]] = { "value": userParameters[userParametersKeys[paramIndex]] }; parameters = _.merge(parameters, item); } } - let template = JSON.parse(fs.readFileSync(templateFilePath, 'utf8')); + let template = JSON.parse(fs.readFileSync(templateFilePath, "utf8")); // Check if there are custom environment variables defined that need to be // added to the ARM template used in the deployment. - const environmentVariables = this.serverless.service.provider['environment']; + const environmentVariables = this.serverless.service.provider["environment"]; if (environmentVariables) { - const appSettingsPath = '$.resources[?(@.kind=="functionapp")].properties.siteConfig.appSettings'; + const appSettingsPath = "$.resources[?(@.kind==\"functionapp\")].properties.siteConfig.appSettings"; jsonpath.apply(template, appSettingsPath, function (appSettingsList) { Object.keys(environmentVariables).forEach(function (key) { @@ -178,7 +178,7 @@ export class FunctionAppService extends BaseService { const deploymentParameters: Deployment = { properties: { - mode: 'Incremental', + mode: "Incremental", parameters, template } @@ -199,10 +199,10 @@ export class FunctionAppService extends BaseService { // TODO: There is a case where the body will contain an error, but it's // not actually an error. These are warnings from npm install. - const response = await this.sendApiRequest('POST', requestUrl, { + const response = await this.sendApiRequest("POST", requestUrl, { data: { command: command, - dir: 'site\\wwwroot' + dir: "site\\wwwroot" } }); @@ -219,8 +219,8 @@ export class FunctionAppService extends BaseService { */ private async getAuthKey(functionApp) { const adminTokenUrl = `${this.baseUrl}${functionApp.id}/functions/admin/token?api-version=2016-08-01`; - const response = await this.sendApiRequest('GET', adminTokenUrl); + const response = await this.sendApiRequest("GET", adminTokenUrl); - return response.data.replace(/"/g, ''); + return response.data.replace(/"/g, ""); } } diff --git a/src/services/loginService.ts b/src/services/loginService.ts index 1faa24b4..05abd722 100644 --- a/src/services/loginService.ts +++ b/src/services/loginService.ts @@ -1,4 +1,4 @@ -import { interactiveLoginWithAuthResponse, loginWithServicePrincipalSecretWithAuthResponse } from '@azure/ms-rest-nodeauth'; +import { interactiveLoginWithAuthResponse, loginWithServicePrincipalSecretWithAuthResponse } from "@azure/ms-rest-nodeauth"; export class AzureLoginService { @@ -16,7 +16,7 @@ export class AzureLoginService { } public static async interactiveLogin() { - await open('https://microsoft.com/devicelogin'); + await open("https://microsoft.com/devicelogin"); return await interactiveLoginWithAuthResponse(); } diff --git a/src/services/resourceService.ts b/src/services/resourceService.ts index fa53d3f3..7ef589c1 100644 --- a/src/services/resourceService.ts +++ b/src/services/resourceService.ts @@ -1,11 +1,11 @@ -import Serverless from 'serverless'; -import { ResourceManagementClient } from '@azure/arm-resources'; -import { BaseService } from './baseService'; +import Serverless from "serverless"; +import { ResourceManagementClient } from "@azure/arm-resources"; +import { BaseService } from "./baseService"; export class ResourceService extends BaseService { private resourceClient: ResourceManagementClient; - constructor(serverless: Serverless, options: Serverless.Options) { + public constructor(serverless: Serverless, options: Serverless.Options) { super(serverless, options); this.resourceClient = new ResourceManagementClient(this.credentials, this.subscriptionId); @@ -15,7 +15,7 @@ export class ResourceService extends BaseService { this.serverless.cli.log(`Creating resource group: ${this.resourceGroup}`); const groupParameters = { - location: this.serverless.service.provider['location'] + location: this.serverless.service.provider["location"] }; return await this.resourceClient.resourceGroups.createOrUpdate(this.resourceGroup, groupParameters); diff --git a/src/shared/binding.test.ts b/src/shared/binding.test.ts index 8ea864a1..1e8fcea5 100644 --- a/src/shared/binding.test.ts +++ b/src/shared/binding.test.ts @@ -1,11 +1,11 @@ -import { MockFactory } from '../test/mockFactory'; -import { BindingUtils } from './bindings'; +import { MockFactory } from "../test/mockFactory"; +import { BindingUtils } from "./bindings"; -describe('Bindings', () => { - it('should get bindings metadata from serverless', () => { +describe("Bindings", () => { + it("should get bindings metadata from serverless", () => { const sls = MockFactory.createTestServerless(); expect(sls).not.toBeNull(); BindingUtils.getBindingsMetaData(sls); - expect(sls.cli.log).toBeCalledWith('Parsing Azure Functions Bindings.json...'); + expect(sls.cli.log).toBeCalledWith("Parsing Azure Functions Bindings.json..."); }); }); \ No newline at end of file diff --git a/src/shared/bindings.ts b/src/shared/bindings.ts index c108072f..e53314b6 100644 --- a/src/shared/bindings.ts +++ b/src/shared/bindings.ts @@ -1,10 +1,10 @@ -import { writeFileSync } from 'fs'; -import { join } from 'path'; -import Serverless from 'serverless'; -import { FunctionMetadata } from './utils'; -import { constants } from './constants'; +import { writeFileSync } from "fs"; +import { join } from "path"; +import Serverless from "serverless"; +import { FunctionMetadata } from "./utils"; +import { constants } from "./constants"; -const bindingsJson = require('./bindings.json'); +const bindingsJson = require("./bindings.json"); // eslint-disable-line @typescript-eslint/no-var-requires export class BindingUtils { public static getBindingsMetaData(serverless: Serverless) { @@ -13,7 +13,7 @@ export class BindingUtils { const bindingSettings = []; const bindingSettingsNames = []; - serverless.cli.log('Parsing Azure Functions Bindings.json...'); + serverless.cli.log("Parsing Azure Functions Bindings.json..."); for (let bindingsIndex = 0; bindingsIndex < bindingsJson[constants.bindings].length; bindingsIndex++) { const settingsNames = []; @@ -41,7 +41,7 @@ export class BindingUtils { const functionJSON = functionMetadata.params.functionsJson; functionJSON.entryPoint = functionMetadata.entryPoint; functionJSON.scriptFile = functionMetadata.handlerPath; - writeFileSync(join(servicePath, functionName, 'function.json'), JSON.stringify(functionJSON, null, 4)); + writeFileSync(join(servicePath, functionName, "function.json"), JSON.stringify(functionJSON, null, 4)); return Promise.resolve(); } @@ -71,11 +71,11 @@ export class BindingUtils { public static getHttpOutBinding(bindingUserSettings) { const binding = {}; - binding[constants.type] = 'http'; + binding[constants.type] = "http"; binding[constants.direction] = constants.outDirection; - binding[constants.name] = '$return'; + binding[constants.name] = "$return"; if (bindingUserSettings[constants.webHookType]) { - binding[constants.name] = 'res'; + binding[constants.name] = "res"; } return binding; @@ -110,7 +110,7 @@ export class BindingUtils { if (defaultValue) { binding[name] = defaultValue; } else if (name === constants.connection && resource.toLowerCase() === constants.storage) { - binding[name] = 'AzureWebJobsStorage'; + binding[name] = "AzureWebJobsStorage"; } else { throw new Error(`Required property ${name} is missing for binding:${bindingType}`); } diff --git a/src/shared/constants.ts b/src/shared/constants.ts index a9dd3512..979bb9a7 100644 --- a/src/shared/constants.ts +++ b/src/shared/constants.ts @@ -1,24 +1,24 @@ export const constants = { - bindings: 'bindings', - settings: 'settings', - name: 'name', - displayName: 'displayName', - type: 'type', - direction: 'direction', - trigger: 'Trigger', - inDirection: 'in', - outDirection: 'out', - value: 'value', - resource: 'resource', - required: 'required', - storage: 'storage', - connection: 'connection', - enum: 'enum', - defaultValue: 'defaultValue', - webHookType: 'webHookType', - httpTrigger: 'httpTrigger', - queue: 'queue', - queueName: 'queueName', - xAzureSettings: 'x-azure-settings', - entryPoint: 'entryPoint' + bindings: "bindings", + settings: "settings", + name: "name", + displayName: "displayName", + type: "type", + direction: "direction", + trigger: "Trigger", + inDirection: "in", + outDirection: "out", + value: "value", + resource: "resource", + required: "required", + storage: "storage", + connection: "connection", + enum: "enum", + defaultValue: "defaultValue", + webHookType: "webHookType", + httpTrigger: "httpTrigger", + queue: "queue", + queueName: "queueName", + xAzureSettings: "x-azure-settings", + entryPoint: "entryPoint" } \ No newline at end of file diff --git a/src/shared/utils.ts b/src/shared/utils.ts index 55234686..96ab9f06 100644 --- a/src/shared/utils.ts +++ b/src/shared/utils.ts @@ -55,7 +55,7 @@ export class Utils { } if (bindingTypeIndex < 0) { - throw new Error('Binding not supported'); + throw new Error("Binding not supported"); } bindingSettings = parsedBindings.bindingSettings[bindingTypeIndex]; @@ -95,13 +95,13 @@ export class Utils { } public static getEntryPointAndHandlerPath(handler) { - let handlerPath = 'handler.js'; + let handlerPath = "handler.js"; let entryPoint = handler; - const handlerSplit = handler.split('.'); + const handlerSplit = handler.split("."); if (handlerSplit.length > 1) { entryPoint = handlerSplit[handlerSplit.length - 1]; - handlerPath = `${handler.substring(0, handler.lastIndexOf('.'))}.js`; + handlerPath = `${handler.substring(0, handler.lastIndexOf("."))}.js`; } const metaData = { entryPoint: entryPoint, diff --git a/src/test/mockFactory.ts b/src/test/mockFactory.ts index da96e62f..c415baf1 100644 --- a/src/test/mockFactory.ts +++ b/src/test/mockFactory.ts @@ -1,8 +1,8 @@ -import { AuthResponse, LinkedSubscription, TokenCredentialsBase } from '@azure/ms-rest-nodeauth'; -import Serverless from 'serverless'; -import Service from 'serverless/classes/Service'; -import Utils = require('serverless/classes/Utils'); -import PluginManager = require('serverless/classes/PluginManager'); +import { AuthResponse, LinkedSubscription, TokenCredentialsBase } from "@azure/ms-rest-nodeauth"; +import Serverless from "serverless"; +import Service from "serverless/classes/Service"; +import Utils = require("serverless/classes/Utils"); +import PluginManager = require("serverless/classes/PluginManager"); export class MockFactory { public static createTestServerless(config?: any): Serverless { @@ -28,10 +28,10 @@ export class MockFactory { public static createTestAuthResponse(): AuthResponse { return { - credentials: 'credentials' as any as TokenCredentialsBase, + credentials: "credentials" as any as TokenCredentialsBase, subscriptions: [ { - id: 'azureSubId', + id: "azureSubId", } ] as any as LinkedSubscription[] } @@ -39,7 +39,7 @@ export class MockFactory { private static createTestService(): Service { return { - getAllFunctions: jest.fn(() => ['function1']), + getAllFunctions: jest.fn(() => ["function1"]), getFunction: jest.fn(), getAllEventsInFunction: jest.fn(), getAllFunctionsNames: jest.fn(),